Codeforces Round #770 (Div. 2)

Codeforces Round #770 (Div. 2)

脑子逐渐好用起来(

A - Reverse and Concatenate

给定一个字符串,对它做 \(k\) 次操作,求可能的最终串,每次操作二选一:

  1. \(s\gets s+\text{rev}(x)\)
  2. \(s\gets \text{rev}(x)+x\)

显然做过一次操作之后,一个串就会变为回文串,之后怎么选都一样。

所以判断 \(k=0\) 与初始串是否为回文串就能简单判断了。

B - Fortune Telling

Alice 一开始有 \(x\),Bob 一开始有 \(x+3\),给他们一个长度为 \(n\) 的序列 \(A\)

他们各自可以对自己的数 \(d\) 做如下变换(二选一),对每一个 \(i\in[1,n]\)

  1. \(d\gets d+a_i\)
  2. \(d\gets d\operatorname{xor}a_i\)

他们中恰有一个人最后可能得到给定的结果 \(g\),求是哪个人。

偏诈骗题。两者操作都是不改变奇偶性的,而 \(x\)\(x+3\) 的奇偶性不同,没了。

C - OKEA

构造一个 \(n\times m\) 的矩阵,要求把 \(1\sim n\times m\) 都填进去。

且对于任意行的任意一个子串,设它长度为 \(L\),那么该子串的和被 \(L\) 整除。

或者输出无解。

比较适合手玩的简单构造题。当 \(n\) 为奇数时,只有 \(m=1\) 有解,平凡。

否则,一定有解,构造方法为 \(1,3,5,7,\cdots\) 连续填,奇数恰好填满一半,然后 \(2,4,6,8,\cdots\)

D - Finding Zero

这是一道交互题。

给定一个有且仅有一个位置为 \(0\) 的序列 \(A\),要求用 \(\leq 2n-2\) 次询问和 \(1\) 次猜测得到该位置。

询问形如 \((i,j,k)\),将返回 \(\max(a_i,a_j,a_k)-\min(a_i,a_j,a_k)\)

猜测形如 \((i,j)\),只要 \(a_i=0\)\(a_j=0\) 即可。以上都满足 \(i\neq j\neq k\)

考虑均摊用 \(2\) 个代价排除一个不可能的数字,就已经符合要求了。

简单思考,不难用 \(\binom{4}{3}=4\) 次排除 \(a,b,c,d\)至少 \(2\) 个数字。

最终统计答案时,可能碰到 \(n'=3\) 的情况,只需要随便找一个已经被排除的数字 \(d\) 来做类似的排除即可。

均摊下来确实是 \(2\) 次排掉 \(1\) 个数字,最坏情况下,当 \(n\) 为奇数,用 \(2n-2\),当 \(n\) 为偶数,用 \(2n-4\)

赛时代码,丑陋不堪(

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 1010;
int n, a[N];

int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

int Ask(int a, int b, int c) {
	fflush(stdout);
	printf("? %d %d %d\n", a, b, c);
	fflush(stdout);
	int now; cin >> now;
	return now;
}

void Ans(int a, int b) {
	if(! b) {b = (a == 1) ? 2 : 1;}
	fflush(stdout);
	printf("! %d %d\n", a, b);
	fflush(stdout);
}

void Work() {
	n = read(); int m = n;
	rep(i, 1, n) a[i] = i;

	while(n >= 4) {
		int A = a[n], B = a[n - 1], C = a[n - 2], D = a[n - 3];
		int S1 = Ask(A, B, C), S2 = Ask(A, B, D);
		int S3 = Ask(A, C, D), S4 = Ask(B, C, D);
		int Mx = max(max(S1, S2), max(S3, S4));
		int num = (S1 == Mx) + (S2 == Mx) + (S3 == Mx) + (S4 == Mx);

		if(num == 4) n -= 4;
		else if(num == 3) {
			n -= 3;
			if(S1 != Mx)
				a[n] = D, a[n + 1] = A, a[n + 2] = B, a[n + 3] = C;		
			else if(S2 != Mx)
				a[n] = C, a[n + 1] = A, a[n + 2] = B, a[n + 3] = D;
			else if(S3 != Mx)
				a[n] = B, a[n + 1] = A, a[n + 2] = C, a[n + 3] = D;
			else if(S4 != Mx)
				a[n] = A, a[n + 1] = B, a[n + 2] = C, a[n + 3] = D;
		}
		else {
			n -= 2;
			if(S1 == Mx && S2 == Mx)
				a[n] = A, a[n - 1] = B, a[n + 1] = C, a[n + 2] = D;
			else if(S1 == Mx && S3 == Mx)
				a[n] = A, a[n - 1] = C, a[n + 1] = B, a[n + 2] = D;
			else if(S1 == Mx && S4 == Mx)
				a[n] = B, a[n - 1] = C, a[n + 1] = A, a[n + 2] = D;
			else if(S2 == Mx && S3 == Mx)
				a[n] = A, a[n - 1] = D, a[n + 1] = B, a[n + 2] = C;
			else if(S2 == Mx && S4 == Mx)
				a[n] = B, a[n - 1] = D, a[n + 1] = A, a[n + 2] = C;
			else if(S3 == Mx && S4 == Mx)
				a[n] = C, a[n - 1] = D, a[n + 1] = A, a[n + 2] = B;
		}
	}
	
	if(n == 3) {
		int A = a[1], B = a[2], C = a[3], D = a[m];
		int S1 = Ask(A, B, C), S2 = Ask(A, B, D);
		int S3 = Ask(A, C, D), S4 = Ask(B, C, D);
		int Mx = max(max(S1, S2), max(S3, S4));
		int num = (S1 == Mx) + (S2 == Mx) + (S3 == Mx) + (S4 == Mx);
		
		if(num == 3) {
			n -= 3;
			if(S1 != Mx) Ans(D, 0);	
			else if(S2 != Mx) Ans(C, 0);
			else if(S3 != Mx) Ans(B, 0);
			else if(S4 != Mx) Ans(A, 0);
		}
		else {
			n -= 2;
			if(S1 == Mx && S2 == Mx) Ans(A, B);
			else if(S1 == Mx && S3 == Mx) Ans(A, C);
			else if(S1 == Mx && S4 == Mx) Ans(B, C);
			else if(S2 == Mx && S3 == Mx) Ans(A, D);
			else if(S2 == Mx && S4 == Mx) Ans(B, D);
			else if(S3 == Mx && S4 == Mx) Ans(C, D);
		}
	}
	else if(n == 2) Ans(a[1], a[2]);
	else Ans(a[1], 0);
}

int main() {
	int T = read();
	while(T --) Work();
	return 0;
}

E - Fair Share

给定 \(n\) 个长度为偶数 \(n_i\) 的序列,要求将所有数字归入集合 \(L/R\) 中。

要求最终 \(L=R\),且每个序列中,恰有 \(n_i/2\) 个归入 \(L\) 中,另一半归入 \(R\) 中。

给出方案或者输出无解。

当某个数字全局出现奇数次时无解,否则一定有解。

因为很多偶数,很难不联想到图论中的欧拉回路,可以构造二分图:

  1. 左部点为:\(1\sim n\) 表示 \(n\) 个序列。
  2. 右部点为:\(1\sim t\) 表示(离散化后)全局出现过的权值。
  3. 连边:序列 \(i\)\(j\) 出现过 \(k\) 次,就连 \(k\)\((i,j)\) 边。

因为度数都是偶数,所以欧拉回路一定存在。

对于最终路径从左往右走的边,代表这个数归入 \(L\),反之归入 \(R\)

每个序列恰有一半在 \(L\) 一半在 \(R\) 的条件自然满足了,因为左部点的入度 = 出度。

两个集合相等也自然满足了,因为右部点的入度 = 出度。

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 4e5 + 10, M = N << 1;
int n, m, t, a[N], b[N], c[N], num[N];
int cnt = 1, head[N], ans[M], frm[N];
bool vis[M], used[N];
struct Edge {int nxt, v;} e[M]; 

int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

void Add(int u, int v) {
	e[++ cnt] = (Edge) {head[u], v}, head[u] = cnt;
	e[++ cnt] = (Edge) {head[v], u}, head[v] = cnt;
}

int stk[N], top;

void Euler(int s) {
	stk[++ top] = s;
	while(top) {
		int u = stk[top], i = head[u];
		used[u] = true;
		while(i && vis[i]) i = e[i].nxt;
		if(i) {
			stk[++ top] = e[i].v;
			ans[i] = (u <= n) ? 1 : 0;
			ans[i ^ 1] = - 1;
			vis[i] = vis[i ^ 1] = true;
			head[u] = e[i].nxt;
		}
		else
			top --;
	}
}

int main() {
	n = read();
	rep(i, 1, n) {
		a[i] = read();
		rep(j, 1, a[i]) b[++ t] = c[t] = read();
	}
	sort(c + 1, c + t + 1);
	m = unique(c + 1, c + t + 1) - (c + 1);
	rep(i, 1, t)
		b[i] = lower_bound(c + 1, c + m + 1, b[i]) - c, 
		num[b[i]] ++;
	rep(i, 1, m) if(num[i] & 1) {puts("NO"); return 0;}
	
	int o = 0;
	rep(i, 1, n)
		rep(j, 1, a[i]) Add(i, b[++ o] + n), frm[o] = cnt;
	
	rep(i, 1, n) if(! used[i]) Euler(i);
	puts("YES"), o = 0;
	rep(i, 1, n) {
		rep(j, 1, a[i]) {
			int now = ans[frm[++ o]];
			if(now == - 1) now = ans[frm[o] ^ 1];
			putchar(now ? 'L' : 'R');
		}
		puts("");
	}
	return 0;
}

F - Fibonacci Additions

给定两个长度均为 \(n\) 的序列 \(A,B\) 和模数 \(p\),以下所有操作均在 \(\bmod p\) 意义下进行。

\(q\) 次修改,每次形如 \((l,r,A/B)\) 表示把 \([l,r]\) 区间加斐波那契,即 \(i\in [l,r],a_i\gets a_i+f_{i-l+1}\)

\(f_1=f_2=1,f_i=f_{i-1}+f_{i-2}(i\geq 3)\)

每次修改后需要回答 \(A,B\) 两个序列是否完全相同。

以为是什么神秘数据结构,看完题解发现是 \(O(n)\) 的。(sto DX 的 998ms 的分块 orz)

因为只需要维护相同性,所以没有那么繁琐。

\(c_i=a_i-b_i\),当它全为 \(0\) 时符合条件,再设 \(d_1=c_1,d_2=c_2-c_1,d_i=c_i-c_{i-1}-c_{i-2}(i\geq 3)\)

不难发现 \(d\) 的全 \(0\) 性和 \(c\) 的全 \(0\) 性是等价的!

但是 \(d\) 很好维护,因为它的定义是与 \(fab\) 类似的,假设对 \(A\),做区间 \((l,r)\) 的修改,那么对 \(d\) 来说,只有:

  1. \(d_l\gets d_l+1\)
  2. \(d_{r+1}\gets d_{r+1}-f_{r-l+2}\)
  3. \(d_{r+2}\gets d_{r+2}-f_{r-l+1}\)

\(B\) 是类似的。这种针对特殊函数构造特殊差分的思想很是神秘(

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 3e5 + 10;
int n, q, P, cnt, a[N], b[N], d[N], f[N];

int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

void Moi(int p, int v) {
	if(p > n) return;
	cnt -= (d[p] != 0);
	d[p] = ((d[p] + v) % P + P) % P;
	cnt += (d[p] != 0);
}

int main() {
	n = read(), q = read(), P = read();
	
	f[1] = f[2] = 1;
	rep(i, 3, n + 5) f[i] = (f[i - 1] + f[i - 2]) % P;
	
	rep(i, 1, n) a[i] = read();
	rep(i, 1, n) b[i] = read();
	rep(i, 1, n) d[i] = (a[i] - b[i] + P) % P;
	per(i, n, 3) d[i] = ((d[i] - d[i - 1] - d[i - 2]) % P + P) % P; 
	if(n >= 2) d[2] = (d[2] - d[1] + P) % P;
	rep(i, 1, n) cnt += (d[i] != 0);
	
	while(q --) {
		char opt[3]; scanf("%s", opt);
		int l = read(), r = read();
		if(opt[0] == 'A')
			Moi(l, 1), Moi(r + 1, - f[r - l + 2]), Moi(r + 2, - f[r - l + 1]);
		else
			Moi(l, - 1), Moi(r + 1, f[r - l + 2]), Moi(r + 2, f[r - l + 1]);
		puts(cnt ? "NO" : "YES");
	}
	return 0;
}
posted @ 2022-02-07 21:37  LPF'sBlog  阅读(107)  评论(0编辑  收藏  举报