考虑DP,设$f[i][j]$表示考虑了$a[1..i]$和$b[1..j]$的最小代价。
若$a[i]==b[j]$,则$f[i][j]=\min(f[i-1][j],f[i][j-1])+1$。
否则找到最大的$t$,满足$x$和$y$往前$t$个均不相等,此时$f[i][j]=f[i-t-1][j-t-1]+t$。
对于$t$,可以通过在相应差值的序列中二分查找得到。
对于DP的计算,可以通过搜索,并将那$n$个$a[i]==b[j]$的状态记忆化。
因为对于每个没有记忆化的状态,均可以在$O(\log n)$的时间内转化为那$n$个状态,所以总时间复杂度为$O(n\log n)$。
#include<cstdio> const int N=1000010,BUF=13778000; int n,m,i,j,a[N],b[N],c[N],f[N],g[N<<1],nxt[N],st[N<<1],en[N<<1],q[N];char Buf[BUF],*buf=Buf; inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} inline void add(int x,int y){nxt[y]=g[x];g[x]=y;} inline int min(int a,int b){return a<b?a:b;} inline int pre(int l,int r,int x){ int t=0,mid; while(l<=r)if(q[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1; return q[t]; } int dp(int x,int y){ if(!x||!y)return x+y; if(a[x]==b[y])return f[x]?f[x]:f[x]=min(dp(x-1,y),dp(x,y-1))+1; int t=pre(st[x-y+n],en[x-y+n],x); return t?dp(t,y-x+t)+x-t:(x>y?x:y); } int main(){ fread(Buf,1,BUF,stdin);read(n); for(i=1;i<=n;i++)read(a[i]); for(i=1;i<=n;i++)read(b[i]),c[b[i]]=i; for(i=n;i;i--)add(i-c[a[i]]+n,i); for(i=1;i<n+n;en[i++]=m)for(st[i]=m+1,j=g[i];j;j=nxt[j])q[++m]=j; return printf("%d",dp(n,n)),0; }
时间: 2024-11-05 22:05:40