[USACO22DEC] Palindromes P 题解
T3 [USACO22DEC] Palindromes P
郝题。首先考虑给定一个串 \(S\) 怎么求出要换多少次。
易得,不可能交换两个本来就相同的字符。不妨观察 \(\texttt G\) 的回文关系,一对 \(\texttt G\) 回文当且仅当第一个 \(\texttt G\) 前面的 \(\texttt H\) 数量等于第二个 \(\texttt G\) 后面的 \(\texttt H\) 的数量。换句话说,若当前的串 \([l,r]\),其中有一对 \(\texttt G\) 的位置为 \((a,b)\),则将这一对 \(\texttt G\) 归位的花费为:
\[\big|(a+b)-(l+r)\big|
\]
简单手模应该不难得到。要注意特殊情况:
- 若串长为偶数但 \(\texttt G\) 的个数为奇数,不可能为回文串,\(-1\) 走人;
- 否则一定存在一个 \(\texttt G\) 在正中间的位置,计算 \(\Big|\mathit{pos}-\big\lfloor(l+r)/2\big\rfloor\Big|\)。
所以我们就有一个 \(O(n^3)\) 的暴力,其中 \(O(n^2)\) 枚举子串,\(O(n)\) 计算答案。类似一个区间 DP 的复杂度,由于跑不满,可以通过 \(n\le2000\) 的数据,实测 36pts。
一般来说想到这里就差不多了。
我们发现可以转变转移方式,由中间向两边扩展。先枚举 \(i\) 作为中点,神奇地用树状数组维护 \(l+r\) 的值统计答案,然后向左向右扩展之后,再将新的 \(l+r\) 扔进树状数组。注意到原来有绝对值的符号,所以还需要维护 \(l+r\) 和的个数,算出 \(<l+r\) 和 \(>l+r\) 的个数,就是一个 \(O(n^2\log n)\) 的做法。题解区还有 \(O(n^2)\) 的做法。
感觉重点还是在于发现这个式子。
#include<bits/stdc++.h>
#define lowbit(x) (x&-x)
using namespace std;
using ll=long long;
constexpr int MAXN=7505;
int t[MAXN],n;
string s;
struct BIT{
ll c[MAXN<<1];
void add(int x,int k){
while(x<=n<<1)c[x]+=k,x+=lowbit(x);
}
ll sum(int x){
ll res=0;
while(x)res+=c[x],x-=lowbit(x);
return res;
}
void clear(){
memset(c,0,sizeof(c));
}
}t1,t2;
int main(){
ios::sync_with_stdio(0);
cin.tie(nullptr),cout.tie(nullptr);
cin>>s;
n=s.size();
s=' '+s;
int c=0;
for(int i=1;i<=n;++i)if(s[i]=='G')t[++c]=i;
t[c+1]=n+1;
ll ans=0,sum=0,lans=0;
for(int i=1;i<=c;++i){
int lf=i,rf=i;
while(lf&&rf<=c){
int fk=t[lf]+t[rf];
if(lf^i){
t1.add(fk,fk),t2.add(fk,1);
sum+=fk;
++lans;
}
for(int l=t[lf];l>t[lf-1];--l)
for(int r=t[rf];r<t[rf+1];++r){
if((r-l+1)%2==0){
--ans;
continue;
}
ll p=t2.sum(l+r-1),q=t1.sum(l+r-1);
ans+=abs((l+r)/2-t[i]);
ans+=(p*(l+r)-q)+(sum-q)-(lans-p)*(l+r);
}
--lf,++rf;
}
sum=lans=0;
t1.clear(),t2.clear();
}
for(int i=1;i<c;++i){
int lf=i,rf=i+1;
while(lf&&rf<=c){
int fk=t[lf]+t[rf];
t1.add(fk,fk),t2.add(fk,1);
sum+=fk;
++lans;
for(int l=t[lf];l>t[lf-1];--l)
for(int r=t[rf];r<t[rf+1];++r){
ll p=t2.sum(l+r-1),q=t1.sum(l+r-1);
ans+=(p*(l+r)-q+(sum-q)-(lans-p)*(l+r));
}
--lf,++rf;
}
sum=lans=0;
t1.clear(),t2.clear();
}
cout<<ans<<'\n';
return 0;
}
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程 $\rm QED$,由上可知证毕。

浙公网安备 33010602011771号