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

Codeforces Round #632 (Div. 2)

A:我用的构造方法是:\(n\times m\)是奇数就黑白相间涂色,左上角涂\(B\)\(n\times m\)是偶数就再把就黑白相间涂色,左上角涂\(W\),最后把左上角涂\(B\)

而这太麻烦,实际上直接第一个格子涂\(B\)即可。

int t, n, m, a[N][N]; 
int main() {
	scanf("%d", &t);
	while(t --) {
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i ++)
			for(int j = 1; j <= m; j ++)
				a[i][j] = (i + j) & 1;
		if(n * m & 1) {
			for(int i = 1; i <= n; i ++, puts(""))
				for(int j = 1; j <= m; j ++)
					printf("%c", !a[i][j] ? 'B' : 'W');
			continue ;
		}
		a[1][1] = 1;
		for(int i = 1; i <= n; i ++, puts(""))
			for(int j = 1; j <= m; j ++)
				printf("%c", a[i][j] ? 'B' : 'W');
	}
	return 0;
}

B:最优操作顺序肯定是先改后面再改前面。直接判一下即可。

int n, a[N], b[N];
int main() {
	int t; scanf("%d", &t);
	while(t --) {
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++) scanf("%d", a + i);
		for(int i = 1; i <= n; i ++) scanf("%d", b + i);
		static bool big[N], small[N]; bool tag = 1;
		bool bg = 0, sm = 0;
		for(int i = 1; i <= n; i ++) {
			big[i] = bg; small[i] = sm;
			if(a[i] > 0) bg = 1;
			if(a[i] < 0) sm = 1;
		}
		for(int i = 1; i <= n; i ++) {
			if(a[i] < b[i] && !big[i]) tag = 0;
			if(a[i] > b[i] && !small[i]) tag = 0;
		}
		puts(tag ? "YES" : "NO");
	}
	return 0;
}

C:对于每个位置\(i\),都会有一个限制表示区间不能包含\([l[i], i]\)。考虑以\(i\)结尾的合法区间个数是\(i - \max_{j = 1}^{i}l[j]\),求和即可。

int n;
ll a[N];
map<ll, ll> Map; 
int main() {
	scanf("%d", &n); ll cnt = 0, up = 0;
	for(int i = 1; i <= n; i ++) {
		scanf("%lld", a + i), a[i] += a[i - 1];
		if(Map[a[i]] || a[i] == 0) {
			up = max(up, Map[a[i]] + 1);
		}
		cnt += i - up;
		Map[a[i]] = i;
	}
	printf("%lld\n", cnt);
	return 0;
}

D:把人的朝向转成01序列。相当于是把一个01序列,每轮可以选若干相邻的\(10\),然后变成\(01\)。这就类似冒泡排序的过程,我们先求一个最小轮数的方案,那一定是每轮尽可能多选\(10\)。然后根据\(k\)把每轮拆开,直到恰好\(k\)轮。如果\(k\)小于最小轮数或大于逆序对数则无解。

const int N = 3000 + 10;
int n, k, a[N], ni, pos[N * N], len, bel[N * N];
char s[N];
int main() {
	scanf("%d%d%s", &n, &k, s + 1);
	for(int i = 1; i <= n; i ++) {
		a[i] = s[i] == 'R';
		for(int j = 1; j < i; j ++)
			ni += a[j] > a[i];
	}
	if(k > ni) return puts("-1"), 0;
	int tmp = 0;
	while(1) {
		bool tag = 0; tmp ++;
		for(int i = 1; i < n; i ++) {
			if(a[i] && !a[i + 1]) {
				tag = 1;
				pos[++ len] = i;
				bel[len] = tmp;
			}
		}
		if(!tag) break ;
		for(int i = len; i >= 1 && bel[i] == tmp; i --)
			swap(a[pos[i]], a[pos[i] + 1]);
	}
	tmp --;
	if(k < tmp) return puts("-1"), 0;
	int op = tmp, x = -1; //printf("tmp = %d\n", tmp);
	for(int i = 1; i <= len && op < k; i ++) {
		if(bel[i + 1] == bel[i]) {
			bel[i] = -- x; op ++;
		}
	}
	for(int i = 1, j; i <= len; ) {
		for(j = i; j < len && bel[j + 1] == bel[i]; j ++) ;
		printf("%d", j - i + 1);
		for(int k = i; k <= j; k ++) printf(" %d", pos[k]);
		puts(""); i = j + 1;
	}
	return 0;
}

E:咕咕咕

F:对于某个\(k\)元素最优方案之一,如果某个数的某个非本身因子没出现,那么把这个数换成其因子答案更优。那么一个方案的imperfection就是max 每个数的最大因子。

于是把\(1,2,..,n\)除去最小素因子排序(即按非本身最大约数排序)依次选取。可以发现一个数选进去的时候其所有因数(除本身)一定也被选进去过了,那么这就是合法且最优方案。

const int N = 5e5 + 10;
int n, c[N];
bool tag[N];
int p[N], pc;
void sieve(int n) {
	c[1] = 1;
	for(int i = 2; i <= n; i ++) {
		if(!tag[i]) p[++ pc] = i, c[i] = i;
		for(int j = 1; j <= pc && i * p[j] <= n; j ++) {
			tag[i * p[j]] = 1;
			if(i % p[j] == 0) {
				c[i * p[j]] = p[j];
				break ;
			}
			c[i * p[j]] = p[j];
		}
	}
}
int main() {
	scanf("%d", &n); sieve(n);
	for(int i = 1; i <= n; i ++) c[i] = i / c[i];
	sort(c + 1, c + n + 1);
	for(int i = 2; i <= n; i ++)
		printf("%d ", c[i]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/hongzy/p/12672753.html