题解:AT_cf17_final_e Combination Lock
困难题,但是场切了。
首先先把字符串处理成若干个数。然后回文串就是要求第一个数和最后一个数相等,以此类推。
首先这个区间加显然很不可做,一个经典套路就是转成差分。考虑回文串在差分上怎么刻画。显然,差分上,第一个位置应该和最后一个位置是相反数,以此类推(这里差分数组最后要加一个零)。
然后这个操作在差分数组上显然就是一个位置单点加,一个位置单点减对吧。这个过程很像权值的“传递”。我们不妨使用边
然后整个题显然都是在模
然后因为你发现,一个联通块内,只要保证和不变,你可以随意钦定每个数的值。所以我们肯定往这方面去想。
设一开始那个数组长度为
你发现如果一个操作横跨前后两边不太方便。于是可以这么处理:
你发现红色的操作和紫色的操作等价。
你发现紫色操作和绿色操作是等价的。
因此我们可以把任何一个操作转换到前半部分。
现在问题就变成了你要使前半部分和后半部分相等。然后有若干联通块,你可以对联通块内数任意赋值,但要满足和为一个定值。
那做法就显然了,联通块内和与后半部分对应的和相等就可以,反之就不行。
AC Code
#include<bits/stdc++.h>
using namespace std ;
const int MAXN = 1e5 + 7 ;
char s[MAXN] ;
int val[MAXN] ;
int d[MAXN] ;
int sz ;
vector<int> dir[MAXN] ;
bool vis[MAXN] ;
int cnt1 , cnt2 ;
void dfs(int u) {
cnt1 += d[u] ;
if (u != (sz + 2) / 2)
cnt2 += d[sz + 1 - u + 1] ;
vis[u] = 1 ;
for (auto v : dir[u]) {
if (vis[v]) continue ;
dfs(v) ;
}
return ;
}
void solve() {
cin >> s + 1 ;
for (sz = 1 ; s[sz] != 0 ; sz ++) ; sz -- ;
for (int i = 1 ; i <= sz + 2 ; i ++) {
dir[i].clear() ;
vis[i] = 0 ;
}
for (int i = 1 ; i <= sz ; i ++) {
val[i] = s[i] - 'a' ;
d[i] = (val[i] - val[i - 1] + 26) % 26 ;
}
d[sz + 1] = (26 - val[sz]) % 26 ;
bool flag = 0 ;
if (sz & 1) {
for (int i = sz + 2 ; i >= (sz + 1) / 2 + 2 ; i --) {
d[i] = d[i - 1] ;
}
d[(sz + 1) / 2 + 1] = 0 ;
sz ++ ;
flag = 1 ;
}
int n ;
cin >> n ;
for (int i = 1 ; i <= n ; i ++) {
int l , r ;
cin >> l >> r ;
if (flag) {
if (l > sz / 2) l ++ ;
if (r >= sz / 2) r ++ ;
}
if (sz / 2 - l + 1 < r - sz / 2) {
//翻转过去
int dl = sz - r + 1 ;
int dr = sz - l + 1 ;
l = dl ;
r = dr ;
}
if (r > sz / 2) {
r = sz / 2 - (r - sz / 2) ;
}
dir[l].push_back(r + 1) ;
dir[r + 1].push_back(l) ;
}
for (int i = 1 ; i <= sz / 2 + 1 ; i ++) {
if (!vis[i]) {
cnt1 = cnt2 = 0 ;
dfs(i) ;
if ((cnt1 + cnt2) % 26 != 0) {
cout << "NO\n" ;
return ;
}
}
}
cout << "YES\n" ;
return ;
}
signed main() {
// freopen("string.in" , "r" , stdin) ;
// freopen("string.out" , "w" , stdout) ;
ios::sync_with_stdio(0) ;
cin.tie(0) ;
cout.tie(0) ;
// int t ;
// cin >> t ;
// while (t--) {
// if (t == 52) {
// t ++ ;
// t -- ;
// }
solve() ;
// }
return 0 ;
}
/*
1
fefjkookjkja
3
1 3
6 7
4 11
*/