P8908 [USACO22DEC] Palindromes P
Solution
模拟赛的题,死在了复杂度分析上。我还是太菜了。
先考虑暴力的做法。
设 \(\texttt{G}\) 为 \(1\),\(\texttt{H}\) 为 \(0\)。
假设枚举到的区间为 \([L,R]\),有 \(k\) 个 \(1\),位置为 \(a_{1\sim k}\),满足其为回文串的充要条件是 \(1\) 是对称的。
当 \([L,R]\) 长度为偶数且 \(1\) 的个数为奇数时显然是无解的。
要满足交换的次数最少,则一定是 \(a_1\) 与 \(a_k\) 交换后关于中心对称,\(a_2\) 与 \(a_{k-1}\) 后关于中心对称等。贡献为 \(| a_i-L-(R-a_{k-i+1})|=| a_i+a_{k-i+1}-L-R|\),即 \(i\) 和 \(k-i+1\) 两个分别在中间的两侧。
每次求可以固定 \(L\),让 \(R\) 往右枚举,把为 \(1\) 的位置记录下来。复杂度 \(\mathcal{O(n^3)}\)。
正解:
若 \(k\) 为奇数,可以固定第 \(\lfloor\frac{k+1}{2}\rfloor\) 的数,偶数同理。每次向两边各扩展一个 \(1\),设分别为 \(a_l,a_r\)。那么 \(L \in (a_{l-1},a_l]\),\(R \in [a_r,a_{r+1})\)。
可以直接枚举 \(L,R\),对于每个 \(L,R\) 只会被枚举一次。因为 \(a_l,a_r\) 中点只有一个(显然的),它只会被枚举到一次,所以 \(L \in (a_{l-1},a_l]\),\(R \in [a_r,a_{r+1})\) 也只会被枚举到一次。
拿树状数组维护有多少个数比 \(L+R\) 大以及它们的和,有多少个数比 \(L+R\) 小以及它们的和。分别计算贡献即可。复杂度 \(\mathcal{O(n^2\log n)}\)。
Code
#include<bits/stdc++.h>
#define IOS cin.tie(0),cout.tie(0),ios::sync_with_stdio(0)
#define ll long long
#define db double
#define pb push_back
#define eb emplace_back
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define PLL pair<ll,ll>
#define PII pair<int,int>
#define I inline
#define Tp template<typename Tt>
#define Ts template<typename Tt,typename ...args>
#define lb(x) ((x)&(-x))
using namespace std;
const int N=7500+20,M=1e5+20;
const ll INF=1ll<<60,mod=998244353;
namespace H_H{
int n,a[N],b[N],cnt;
struct BIT{
ll s[N<<1],p[N<<1];
inline void clear(){MS(s,0);MS(p,0);}
inline void add(int x){
int tp=x;
for(;x<=2*n;x+=lb(x)) s[x]+=tp,p[x]+=1;
}
inline PLL query(int x){
ll ans=0,Ans=0;
for(;x;x-=lb(x)) ans+=s[x],Ans+=p[x];
return {ans,Ans};
}
}bit;
PLL operator - (const PLL xx,const PLL yy){
return {xx.first-yy.first,xx.second-yy.second};
}
inline void input(){
char ch;
while(cin>>ch) a[++n]=ch=='G';
}
int main(){
input();
ll ans=0;
for(int l=n;l;l--){
cnt=0;
for(int r=l;r<=n;r++){
if(a[r]) b[++cnt]=r;
if((r-l)&1 && cnt&1){//无解
ans--;
continue;
}
if(cnt&1) ans+=abs(((l+r)>>1)-b[(cnt>>1)+1]);
}
}
b[cnt+1]=n+1;
for(int i=1;i<cnt;i++){//k 为偶数
bit.clear();
for(int l=i,r=i+1;l>=1 && r<=cnt;l--,r++){
bit.add(b[l]+b[r]);
for(int L=b[l-1]+1;L<=b[l];L++){
for(int R=b[r];R<=b[r+1]-1;R++){
int num=L+R;
PLL num_1=bit.query(num);
PLL num_2=bit.query(2*n)-num_1;
ans+=(num_1.second-num_2.second)*num+num_2.first-num_1.first;
}
}
}
}
for(int i=2;i<cnt;i++){//k 为奇数
bit.clear();
for(int l=i-1,r=i+1;l>=1 && r<=cnt;l--,r++){
bit.add(b[l]+b[r]);
for(int L=b[l-1]+1;L<=b[l];L++){
for(int R=b[r];R<=b[r+1]-1;R++){
if((L-R)&1) continue;
int num=L+R;
PLL num_1=bit.query(num);
PLL num_2=bit.query(2*n)-num_1;
ans+=(num_1.second-num_2.second)*num+num_2.first-num_1.first;
}
}
}
}
cout<<ans<<"\n";
return 0;
}
}
int main(){
IOS;H_H::main();
return 0;
}

浙公网安备 33010602011771号