Codeforces Round #779 (Div. 2)

CF1658A Marin and Photoshoot

任意两个 0 之间至少有两个 1,不够就补上。

char s[MAXN];

int main() {
	int T;
	read(T);
	while(T -- > 0) {
		int n;read(n);
		scanf("%s" , s + 1);
		int ans = 0;
		for (int i = 1; i < n; ++i) if(s[i] == '0') {
			if(s[i + 1] == '0') ans += 2;
			else if(s[i + 2] == '0') ans ++;
		}
		write(ans);
	}
	return 0;
}

CF1658B Marin and Anti-coprime Permutation

说真的,很有意思。

人类思维:明显有特解,奇数放偶位,偶数放奇位,观察样例发现很可能是充分必要条件。

于是尝试推广,设 \(\gcd\)\(x\) ,则 \([1,n]\) 中是 \(x\) 倍数的有 \(\lfloor \frac{n}{x} \rfloor\) 个。

然后因此 \(x > 2\) 时我们肯定无法让每个位置都被 \(x\) 整除,于是之前的观察很对。

const int mod = 998244353;

int main() {
	int T;
	read(T);
	while(T -- > 0) {
		int n;read(n);
		if(n & 1) {
			puts("0");
			continue;
		}
		LL ans = 1;
		for (int i = 1; i <= n / 2; ++i) ans = ans * i % mod;
		ans = ans * ans % mod;
		write(ans);
	}
	return 0;
}

CF1658C Shinju and the Lost Permutation

同样是观察,发现有特殊情况。即当最大值在最前面的时候 b1

之后继续循环位移,发现一次最多增加 1 或者减少很多,发现如果满足该性质我一定能通过建立拓扑序构造解,因此又是一个充分必要条件,模拟一下就好。

const int MAXN = 2e5 + 5;

int c[MAXN] , n;

int main() {
	int T;
	read(T);
	while(T -- > 0) {
		read(n);
		int num = 0;
		for (int i = 1; i <= n; ++i) read(c[i]),c[i + n] = c[i] , num += (c[i] == 1);
		if(num != 1) {
			puts("NO");
			continue;
		}
		for (int i = 1; i <= n; ++i) if(c[i] == 1) num = i;
		int fl = 1;
		for (int i = 1; i < n; ++i) if(c[i + num] - c[i + num - 1] > 1) {
			fl = 0;
			break;
		}
		if(fl) puts("YES");
		else puts("NO");
	}
	return 0;
}

CF1658D

没考虑过 D1 的特别做法,直接做的通解。

\([l,r]\) 是排列的一部分,所以互不相同,异或上一个数后还是互不相同。

考虑我得到的序列,枚举哪个数字是 \(l\) 变化过来的,于是就能枚举到 \(x\) ,由于给定数互不相同,所以异或上 \(x\) 也互不相同,只要保证这些数异或上 \(x\) 的最小值是 \(l\) ,最大值是 \(r\) 就好了。

具体用 01-trie 实现。

const int MAXN = (1 << 17) + 5;

int num , ch[MAXN * 17][21];
void Insert(int x) {
	int cur = 1;
	for (int i = 16; i >= 0; --i) {
		int k = (x >> i) & 1;
		if(!ch[cur][k]) ch[cur][k] = ++num;
		cur = ch[cur][k];
	}
}

int calc(int x , int ty) {
	int cur = 1 , ans = 0;
	for (int i = 16; i >= 0; --i) {
		int k = (x >> i) & 1;
		if(ch[cur][k ^ ty]) {
			cur = ch[cur][k ^ ty];
			ans += (ty) << i;
		}
		else if(ch[cur][k ^ ty ^ 1]) {
			cur = ch[cur][k ^ ty ^ 1];
			ans += (ty ^ 1) << i;
		} 
		else break;
	}
	return ans;
}

int a[MAXN];

int main() {
	int T;
	read(T);
	while(T -- > 0) {
		num = 1;int l , r;
		read(l),read(r);
		for (int i = 1; i <= r - l + 1; ++i) {
			read(a[i]);
			Insert(a[i]);
		}
		for (int i = 1; i <= r - l + 1; ++i) {
			int x = a[i] ^ l;
			if(calc(x , 0) == l && calc(x , 1) == r) {
				write(x);
				break;
			}
		}
		for (int i = 1; i <= num; ++i) ch[i][0] = ch[i][1] = 0;
	}
	return 0;
}

CF1658E Gojou and Matrix Game

一个数开始,如果不能走到一个比它大的数,那先手必胜,否则看能否一步走到先手必胜点。

于是从大到小枚举转移,判断能否到达比它大的先手必胜点。

具体用曼哈顿转切比雪夫,用树状数组维护切比雪夫坐标。

const int N = 8000;
const int C = 4000;

int v[2005][2005] , ans[2005][2005];
pii pos[2005 * 2005];

struct BIT {	
	int tr[N + 5];
	void update(int x , int y) {for (; x <= N; x += (x & (-x))) tr[x] += y;}
	int find(int x) {int res = 0;for (; x; x -= (x & (-x))) res += tr[x];return res;}
}T[2];

int main() {
	int n , k;
	read(n),read(k);
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) read(v[i][j]) , pos[v[i][j]] = mp(i , j);
	
	for (int i = n * n; i >= 1; --i) {
		int X = pos[i].fs + pos[i].sc , Y = pos[i].fs - pos[i].sc + C;
		
		int cur = 0;
		if(X - k - 1 >= 1) cur += T[0].find(X - k - 1);
		if(X + k + 1 <= N) cur += T[0].find(N) - T[0].find(X + k);
		if(Y - k - 1 >= 1) cur += T[1].find(Y - k - 1);
		if(Y + k + 1 <= N) cur += T[1].find(N) - T[1].find(Y + k);
		
		if(!cur) ans[pos[i].fs][pos[i].sc] = 1 , T[0].update(X , 1) , T[1].update(Y , 1); 	
	}
	
	for (int i = 1; i <= n; ++i , puts("")) for (int j = 1; j <= n; ++j) {
		if(ans[i][j]) putchar('M');
		else putchar('G');
	}
	
	return 0;
}

CF1658F Juju and Binary String

更加厉害的观察题。

有无解很好判断。观察从每个数开始后面 \(m\) 个数的 1 的个数,记为 \(c_i\)(将序列视为环),则 \(c_i\) 每次变化量为 \(1\)。则必有 \(c_i = m\)

因此只用最多两步完成构造。

const int MAXN = 4e5 + 5;

int n , m , c[MAXN];
char s[MAXN];

int main() {
	int T;
	read(T);
	while(T -- > 0) {
		read(n),read(m);
		scanf("%s" , s + 1);
		LL num = 0;
		for (int i = 1; i <= n; ++i) {
			s[i + n] = s[i];
			num += (s[i] - '0');
		}
		if(num * m % n != 0) {
			puts("-1");
			continue;
		}
		c[n + 1] = 0;
		for (int i = 1; i <= m; ++i) c[n + 1] += s[i] - '0';
		for (int i = n; i >= 1; --i) c[i] = c[i + 1] + (s[i] - '0') - (s[i + m] - '0');
		for (int i = 1; i <= n; ++i) {
			if(c[i] == num * m / n) {
				if(i + m - 1 <= n) {
					puts("1");
					write(i , ' ') , write(i + m - 1);
				}
				else {
					puts("2");
					write(1 , ' ') , write(i + m - 1 - n);
					write(i , ' ') , write(n);
				}
				break;
			}
		}
		
	}
	return 0;
}
posted @ 2022-03-30 22:42  Reanap  阅读(42)  评论(0编辑  收藏  举报