Codeforces Round #620 (Div. 2) 简要题解

Codeforces Round #620 (Div. 2)

A:a + b整除y - x的时候可以跳到一起。

int main() {
	int t; scanf("%d", &t);
	while(t --) {
		int x, y, a, b;
		scanf("%d%d%d%d", &x, &y, &a, &b); y -= x;
		printf("%d\n", y % (a + b) == 0 ? (y / (a + b)) : -1);
	}
	return 0;
} 

B:因为串长都一样所以好做。如果是本身是回文串,出现了奇数次就拿一个放中间,其他放两边。如果不是回文串但原串和反串各出现x, y次,两边接上min(x, y)对。

int n, m, f[N], g[N];
char s[110][110];
bool same(int u, int v) {
	for(int i = 1; i <= m; i ++)
		if(s[u][i] != s[v][i]) return 0;
	return 1; 
}
bool rev(int u, int v) {
	for(int i = 1; i <= m; i ++)
		if(s[u][i] != s[v][m - i + 1]) return 0;
	return 1; 
}
void print(int u) {
	printf("%s", s[u] + 1);
}
void pf(int u) {
	for(int i = m; i >= 1; i --) putchar(s[u][i]);
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) {
		scanf("%s", s[i] + 1);
		bool t = 0;
		for(int j = 1; j < i; j ++) {
			if(same(i, j)) { f[j] ++; t = 1; break ; }
			if(rev(i, j)) { g[j] ++; t = 1; break ; }
		}
		if(t) { i --; n --; continue ; }
		f[i] = 1;
	}
	int len = 0, mid = 0, midx;
	vector<int> ans;
	for(int i = 1; i <= n; i ++) {
		if(rev(i, i)) {
			len += 2 * m * (f[i] / 2);
			for(int j = f[i] / 2; j >= 1; j --)
				ans.push_back(i);
			if(f[i] % 2 == 1) { mid = 1; midx = i; }
		} else {
			for(int j = min(f[i], g[i]); j >= 1; j --)
				ans.push_back(i);
			len += 2 * m * min(f[i], g[i]); 
		}
	}
	printf("%d\n", len + mid * m);
	for(int i = 0; i < (int) ans.size(); i ++) print(ans[i]);
	if(mid) print(midx);
	for(int i = (int) ans.size() - 1; i >= 0; i --) pf(ans[i]);
	return 0;
} 

C:每次维护一个区间,表示这个区间里的温度都可以达到。如果发现上一轮的区间转移不到当前要求区间就NO。

struct Node { int t, l, r; } a[N];
int q, n, m;
int main() {
	scanf("%d", &q);
	while(q --) {
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i ++)
			scanf("%d%d%d", &a[i].t, &a[i].l, &a[i].r);
		int ql = m, qr = m; bool fail = 0;
		for(int i = 1; i <= n; i ++) {
			int nl = a[i].l, nr = a[i].r, dt = a[i].t - a[i - 1].t;
			if(nr < ql - dt || nl > qr + dt) { fail = 1; break ; }
			ql -= dt; qr += dt; ql = max(ql, nl); qr = min(qr, nr);
		}
		puts(fail ? "NO" : "YES");
	}
	return 0;
} 

D:

LIS最短:容易知道答案>= max(连续'<'长度) + 1.可以构造出恰等于的情况:每次分一个连续段从最大的一段取。

LIS最长:容易知道答案<= max('<'个数 + 1, '>'段个数)。容易知道前者更大,于是构造恰等于'<'个数 + 1的排列:维护l, r初始为1,p[1] = 1。若是小于就分配++ r否则分配-- l,最后在把值域换成[1, n],显然正确。当然也可以仿照LIS最短做。

int n, x[N], ans[N];
char s[N];
int main() {
	int t; scanf("%d", &t);
	while(t --) {
		scanf("%d%s", &n, s + 2);
		int l = 1, r = n;
		for(int i = 2; i <= n; ) {
			int j = i;
			for(; j < n && s[j + 1] == s[i]; j ++) ;
			if(s[i] == '<') {
				for(int k = j; k >= i; k --) x[k] = r --;
				if(i == 2) x[1] = r --;
				else {
					int t = x[i - 1];
					for(int k = i; k <= j; k ++) x[k - 1] = x[k];
					x[j] = t;
				}
			} else {
				if(i == 2) x[1] = r --;
				for(int k = i; k <= j; k ++) x[k] = r --;
			}
			i = j + 1; 
		}
		for(int i = 1; i <= n; i ++) printf("%d%c", x[i], " \n"[i == n]);
		
		x[1] = 1; l = 1, r = 1; int mp = 1;
		for(int i = 2; i <= n; i ++) {
			if(s[i] == '<') x[i] = ++ r;
			else x[i] = -- l;
			mp = min(mp, x[i]);
		}
		if(mp != 1) { for(int i = 1; i <= n; i ++) x[i] -= mp - 1; }
		for(int i = 1; i <= n; i ++) printf("%d%c", x[i], " \n"[i == n]);
	}
	return 0;
} 

E:我们只需求出a->b,a->x->y->b, a->y->x->b这三条路径是不是 + 2N = k。

bool ok(int x, int y) {
	return x <= y && (y - x) % 2 == 0;
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i < n; i ++) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].pb(v); G[v].pb(u);
	}
	dfs(1, 0);
	scanf("%d", &q);
	for(int i = 1; i <= q; i ++) {
		int x, y, a, b, k;
		scanf("%d%d%d%d%d", &x, &y, &a, &b, &k);
		int d = dis(a, b); bool tag = 0;
		if(ok(d, k)) tag = 1;
		if(ok(dis(a, x) + dis(b, y) + 1, k)) tag = 1;
		if(ok(dis(a, y) + dis(b, x) + 1, k)) tag = 1;
		puts(tag ? "YES" : "NO");
	}
	return 0;
} 

F:dp[i][j]表示前i行的答案,其中第i行选[i, j]。单调队列转移

const int N = 62, M = 4e4 + 10;
int n, m, k, a[N][M], s[N][M], dp[N][M];
int calc(int x, int y) {
	return s[x][y + k - 1] - s[x][y - 1] + s[x + 1][y + k - 1] - s[x + 1][y - 1];
}
int main() {
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 1; i <= n; i ++) {
		for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]);
		for(int j = 1; j <= m + k; j ++) s[i][j] = s[i][j - 1] + a[i][j];
	}
	for(int i = 1; i <= m; i ++) dp[1][i] = calc(1, i);
	static int q[M], l, r;
	for(int i = 2; i <= n; i ++) {
		l = r = 0; int Max = -2e9;
		for(int j = 1; j <= m; j ++) {
			if(j - k >= 1) Max = max(Max, dp[i - 1][j - k]);
			while(l < r && dp[i - 1][q[r - 1]] - s[i][q[r - 1] + k - 1] <= dp[i - 1][j] - s[i][j + k - 1]) r --;
			q[r ++] = j;
			while(l < r && q[l] + k - 1 < j) l ++;
			dp[i][j] = calc(i, j) + max(Max, dp[i - 1][q[l]] - s[i][q[l] + k - 1] + s[i][j - 1]);
		}
		l = r = 0; Max = -2e9;
		for(int j = m; j >= 1; j --) {
			if(j + k <= m) Max = max(Max, dp[i - 1][j + k]);
			while(l < r && dp[i - 1][q[r - 1]] + s[i][q[r - 1] - 1] <= dp[i - 1][j] + s[i][j - 1]) r --;
			q[r ++] = j;
			while(l < r && q[l] >= j + k) l ++;
			dp[i][j] = max(dp[i][j], calc(i, j) + max(Max, dp[i - 1][q[l]] + s[i][q[l] - 1] - s[i][j + k - 1]));
		}
	}
	int ans = 0;
	for(int i = 1; i <= m; i ++) ans = max(ans, dp[n][i]);
	printf("%d\n", ans);
	return 0;
} 
posted @ 2020-02-16 12:51  hfhongzy  阅读(232)  评论(0编辑  收藏  举报