URAL1966 Cipher Message 3
题解:
能看出来的是,每一组数只能改最后一位,所以前$7$位动不了。
所以$KMP$跑一跑。
重点在于最后一位怎么搞。
如果$KMP$跑完了还没找到合适的位置,直接$puts("No")$就好了。
剩下个匹配问题。
(要不是数据范围拦着我我都想建图跑费用流了)
这个匹配可以用$FFT$求。
$FFT$不是求$\sum(a[i]*b[j-i])$的吗?怎么求字符串匹配?
其实我们只想要最后多项式中某一位上的值,所以$b[j-i]$和$b[i]$没有区别,反转数组就好了。
我们要求的是需要多少个$0$变成$1$,以及多少个$1$变成$0$。
所以$FFT$求两遍卷积,第一次$a[i]=[s1[i]==0],b[i]=[s2[i]==1]$,注意这里的$b$还没有反转。
第二次反过来就可以了。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef unsigned long long ull; const int N = 270050; const ull seed = 131; const double Pi = acos(-1.0); template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } struct cp { double x,y; cp(){} cp(double x,double y):x(x),y(y){} cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);} cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);} cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }; int to[4*N],lim=1,l; void fft(cp *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int o=0;o<i;o++,w=w*w0) { cp w1 = a[j+o],w2 = a[j+o+i]*w; a[j+o] = w1+w2; a[j+o+i] = w1-w2; } } } if(k==-1) for(int i=0;i<len;i++) a[i].x/=len; } void rd(int n,int *a1,int *a2) { for(int x,i=1;i<=n;i++) { read(x); a1[i] = x%10; a2[i] = x/10; } } int n,m,a[2][N],b[2][N]; bool vis[N]; int ans[N]; cp c1[4*N],c2[4*N],c3[4*N]; int nxt[N]; void get_nxt(int *a,int len) { int i = 1,j = 0; while(i<=len) { if(!j||a[i]==a[j]) { i++,j++; nxt[i] = j; }else j = nxt[j]; } } int kmp(int *a,int la,int *b,int lb) { int ret = 0; int i = 1,j = 1; while(i<=la) { if(a[i]==b[j]||j==0) { i++,j++; if(j==lb+1) { vis[i-1]=1; j = nxt[j]; ret = 1; } }else j=nxt[j]; } return ret; } void work() { fft(c1,lim,1),fft(c2,lim,1); for(int i=0;i<lim;i++)c3[i]=c1[i]*c2[i]; fft(c3,lim,-1); } void init() { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(ans,0,sizeof(ans)); memset(vis,0,sizeof(vis)); lim=1,l=0; } int main() { // freopen("tt.in","r",stdin); while(scanf("%d%d",&n,&m)>0) { init(); rd(n,a[0],a[1]),rd(m,b[0],b[1]); get_nxt(b[1],m); if(!kmp(a[1],n,b[1],m)) { puts("No"); continue; } puts("Yes"); while(lim<2*(n+m))lim<<=1,l++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1))); for(int i=0;i<lim;i++)c1[i]=c2[i]=cp(0,0); for(int i=0;i<n;i++)c1[i].x=(a[0][i+1]==1); for(int i=0;i<m;i++)c2[i].x=(b[0][m-i]==0); work(); for(int i=0;i<n;i++)ans[i+1]=(int)(c3[i].x+0.5); for(int i=0;i<lim;i++)c1[i]=c2[i]=cp(0,0); for(int i=0;i<n;i++)c1[i].x=(a[0][i+1]==0); for(int i=0;i<m;i++)c2[i].x=(b[0][m-i]==1); work(); for(int i=0;i<n;i++)ans[i+1]+=(int)(c3[i].x+0.5); int mn = N,pos=0; for(int i=m;i<=n;i++) if(vis[i]&&ans[i]<mn) { mn = ans[i]; pos = i-m+1; } printf("%d %d\n",mn,pos); } return 0; }