题解:AT_cf17_final_e Combination Lock
zhangxiaoyu008 · · 题解
简单题,场切了(感觉 T2 < T1),写一篇题解。
因为要一段同时加一(最后看模
这样原题就转变为每次可以进行
而这个操作相当于可以任意互相调整
我们考虑到最后需要满足对称的数的和必须是
其实考试大概到这里就可以写代码了,因为样例都是对的,即使是错的,写这个也浪费不了多少时间。
考虑充分性,我们对于每个联通块^2分别考虑。
可以把联通块^1视为点,然后取的图的生成树,然后从叶子考虑,把连接叶子与父亲点的两个内部点分别设为叶子联通块^1的值和叶子联通块^1的值的相反数,父亲点的值加上叶子联通块^1的值,把叶子里的其他内部点设为
这里还有个需要想清楚的问题,就是外一某次父亲点只剩一个点,删除之后,父亲点就没有其他点了,是不是就不一定能满足父亲点的和的限制了?
:::info[解答] 若父亲点是根,肯定没问题,如果不是根,那说明这一个点在第二次合并时连接了两个点,这是不可能的,因为一个点在第二次合并时只会连接其对应点,不会再连其他的点。 :::
至此,就做完了。
:::info[赛事代码]{open}
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int T, n, m, l, r, p[N], sum[N];
char s[N];
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int x, int y) {
x = find(x), y = find(y);
if(x != y) {
p[x] = y;
sum[y] += sum[x];
}
}
void solve() {
scanf("%s", s + 1);
n = strlen(s + 1);
for(int i = 1; i <= n + 1; i ++) {
p[i] = i;
sum[i] = s[i] - s[i - 1];
}
scanf("%d", &m);
while(m --) {
scanf("%d%d", &l, &r);
merge(l, r + 1);
}
for(int i = 1, j = n + 1; i < j; i ++, j --) merge(i, j);
for(int i = 1; i <= n + 1; i ++)
if(find(i) == i && (sum[i] % 26)) {
printf("NO\n");
return;
}
printf("YES\n");
}
int main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
scanf("%d", &T);
while(T --) solve();
return 0;
}
:::
P.S. 此题被搬到模拟赛 T2 -> 提高级模拟赛:青紫黑黑