题解 P8908 [USACO22DEC] Palindromes P

· · 题解

先考虑对于整个数组怎么求出最小代价。

首先如果 0,1 均出现了奇数次那么它不可能重排为回文串,直接贡献 -1。否则令 m 表示 1 的个数,考虑每个 1 最终去到了哪。假设最初 1 所在位置构成的序列 a,最终 1 所在位置构成的序列为 b,那么这是一个类似匹配的问题,贪心,把 a,b 从小到大排序后 \sum |a_i-b_i| 即为答案。

接下来优化这个 dp,有个显然的想法是对每个 $a_i(i\le \frac{m}{2})$ 取匹配点 $i$ 使得 $|i-a_i|+|n-i+1-a_{m-i+1}|$ 最小,问题在于这样取出来的 $b_i$ 可能不单调。注意到 $|i-a_i|+|n-i+1-a_{m-i+1}|=|i-a_i|+|i-(n+1-a_{m-i+1})|$,那么当 $i$ 落在 $[a_i,n+1-a_{m-i+1}]$ 时式子取得最小值。考虑 $a$ 的前半边是否落在 $\frac{n}{2}$ 左边,如果是,令 $b_i=a_i$ 即满足条件。否则,令 $b_i=n+1-a_{m-i+1}$ 则满足条件。那么答案即为 $\sum_i |a_i+a_{m-i+1}-(n+1)|$,不需要 dp。复杂度变为 $O(n^3)$,可以通过前五个点。 然后转为枚举 $a_i,a_{m-i+1}$ 计算它们配对产生的贡献。还是记 $a$ 为整个数组中 $1$ 的位置序列,如果两个位置 $a_i,a_j$ 想要配对的话首先有 $l\le a_i,r\ge a_j$,同时如果 $j-i+1$ 为奇数那么 $r-l+1$ 应当也为奇数。对于每个合法的 $l,r$,$a_i,a_j$ 的贡献为 $|a_i+a_j-(l+r)|$。如果事先知道所有 $[l,r]$ 的信息是不是就好办了,不难发现 $i,j$ 对应的信息可以由 $i-1,j+1$ 递推而来。那么考虑从 $a$ 的每段前缀以及每段后缀出发,每次砍掉首尾的两个元素,把新产生的 $[l,r]$ 加进一个数据结构里。而这里新产生的 $[l,r]$ 其实就是 $l\in(a_{i-1},a_i],r\in[a_j,a_{j+1})$ 对应的所有区间,于是可以枚举 $l+r$ 简单地算出 $l+r$ 的出现次数,然后一并插入数据结构。 现在看看这个数据结构需要支持什么:维护一个可重集,支持:插入 $c$ 个 $x$,查询所有 $\le x$ 的元素之和以及元素个数。由于 $x\le 2n$,只需要用一个树状数组。复杂度 $O(n^2\log n)$。有一个细节是让出现次数较少的值作为 $1$,这样可以省去一半的常数。 代码如下:(码字不易,能不能点个赞再走QAQ) ```cpp #include<bits/stdc++.h> namespace vectorwyx{ #define pii pair<int,int> #define fi first #define se second #define pb push_back #define eb emplace_back #define mk make_pair #define sml(x,y) (x=min(x,y)) #define big(x,y) (x=max(x,y)) #define ll long long #define uint unsigned #define ull unsigned long long #define umap unordered_map #define db double #define fo(i,x,y) for(int i=(x);i<=(y);++i) #define go(i,x,y) for(int i=(x);i>=(y);--i) #define ptc putchar #define emp emplace #define re return #define co continue #define brk break #define HH (ptc('\n')) #define bctz __builtin_ctz #define bclz __builtin_clz #define bppc __builtin_popcount using namespace std; ll seed=chrono::system_clock::now().time_since_epoch().count(); mt19937 rnd(seed); inline int rm(int x,int y){return (int)(rnd()%(y-x+1ll)+x);} inline int read(){signed ch=getchar();int x=0,f=1;while(!isdigit(ch)){if(ch==(int)('-'))f=-1;ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;} inline void out(int *a,int l,int r){fo(i,l,r) cout<<*(a+i)<<' ';puts("");} const int N=7505,inf=1e9; int cnt;ll sum; namespace BIT{ int n; pair<int,ll> tr[N<<1]; #define lbit(x) (x&(-x)) void upd(int c,int k){//插入 c 个 k // printf("upd(%d,%d)\n",c,k); sum+=(ll)c*k;cnt+=c; int x=k; while(x<=n){ tr[x].fi+=c,tr[x].se+=(ll)c*k; x+=lbit(x); } } int ask_cnt(int x){ int ret=0; while(x){ ret+=tr[x].fi; x-=lbit(x); } re ret; } ll ask_sum(int x){ ll ret=0; while(x){ ret+=tr[x].se; x-=lbit(x); } re ret; } void clear(){fo(i,1,n) tr[i]=mk(0,0);} } using BIT::upd; using BIT::ask_cnt; using BIT::ask_sum; using BIT::clear; int a[N],n,c0[N],c1[N],b[N],m,pos[N],ct; ll ans; inline void play(int l,int r,int L,int R,bool fl){ r-=l,R-=L; fo(x,0,r+R) if(!fl||(x+l+L)%2==0){ int lx=max(0,x-R),rx=min(x,r); // int c=fl?(rx/2-(lx-1)/2):(rx-lx+1); int c=(rx-lx+1); upd(c,x+l+L); } } void shrink(int l,int r){ int fl=(r-l+1)&1; sum=0;cnt=0; clear(); while(l<=r){ // printf("[%d,%d]\n",l,r); // fo(j,pos[l-1]+1,pos[l]) fo(k,pos[r],pos[r+1]-1) // if(!fl||((k-j+1)&1)) upd(1,j+k),sum+=j+k,cnt++; play(pos[l-1]+1,pos[l],pos[r],pos[r+1]-1,fl); int x=pos[l]+pos[r]; ll val=sum-2*ask_sum(x)+(ll)x*(2*ask_cnt(x)-cnt); // printf("cnt=%d sum=%lld x=%d val=%lld\n",cnt,sum,x,val); if(l==r){ assert(val%2==0); ans+=val/2; }else ans+=val; // printf("now ans=%lld\n",ans); l++,r--; } } signed main(){ int ch=getchar();while(ch!='G'&&ch!='H') ch=getchar(); while(ch=='G'||ch=='H') a[++n]=ch=='G',ch=getchar(); { int c=0;fo(i,1,n) c+=a[i]; if(c>n/2) fo(i,1,n) a[i]^=1; } BIT::n=2*n; // cout<<n<<'\n';out(a,1,n); fo(i,1,n){ c0[i]=c0[i-1]+(a[i]==0); c1[i]=c1[i-1]+(a[i]==1); } fo(i,1,n) if(a[i]) pos[++ct]=i; pos[ct+1]=n+1; // cout<<"pos:";out(pos,0,ct+1); fo(i,1,ct) shrink(1,i); fo(i,2,ct) shrink(i,ct); fo(l,1,n) fo(r,l+1,n){ int x=c0[r]-c0[l-1],y=c1[r]-c1[l-1]; if((x&1)&&(y&1)) ans--; } cout<<ans; return 0; } } /* GHHGGHHGH ------------------------------------------------- 12 */ signed main(){re vectorwyx::main();} ```