Description
CJB天天要跟妹子聊天,可是他对微信的加密算法表示担心:“微信这种加密算法,早就过时了,我发明的加密算法早已风靡全球,安全性天下第一!”
CJB是这样加密的:设CJB想加密的信息有 m 个字节。首先,从网上抓来一张 n(n≥m) 个字节的图片,分析里面的每个字节(byte)。每个字节有8位(bit)二进制数字。他想替换掉某些字节中最低位的二进制数字,使得这张图片中,连续 m 个字节恰为他想加密的信息。这样,图片看起来没什么区别,却包含了意味深长的信息。
很显然,不是所有的图片都能让CJB加密他那 m 个字节的信息。他想请你帮忙写个程序判断这张图片是否能加密指定的信息。如果可以加密,则CJB要求改变最少的字节数。如果仍有多种解,他希望信息在图片中的位置越前越好。
Input
第一行包含两个整数 n,m(1≤n,m≤250000) ,表示图片的大小和信息的大小。
第二行表示图片的内容。
第三行表示信息的内容。
所有内容都以二进制字节的形式给出。每个字节有8位,最左边是最高位,最右边为最低位。
Output
如果这张图片不能加密这些信息,输出No
否则第一行输出Yes,第二行输出两个整数:最少修改的字节数,加密信息的起始位置。如果有多组解,要求加密信息的起始位置尽量前。
Sample Input
【样例输入1】
3 2
11110001 11110001 11110000
11110000 11110000
【样例输入2】
3 1
11110000 11110001 11110000
11110000
Sample Output
【样例输出1】
Yes
1 2
【样例输出2】
Yes
0 1
HINT
【样例解释】
图片有3个字节,信息有2个字节。
图片前两个字节可以匹配信息,需要改变两个字节中的最低位。
图片后两个字节可以匹配信息,只需要改变一个字节(第二个字节)中的最低位,信息在图片中的起始位置为第2个字节。
【数据范围与约定】
对于10%的数据, n,m≤500
对于40%的数据, n,m≤5000
对于70%的数据, n,m≤105
对于所有数据, 1≤n,m≤2.5×105
题解:
对于每个二进制除最后一位的数都必须与原串匹配,可以用KMP做
对于每个二进制最后一位需计算与原串最后一位不同的个数,可用FFT做:
将原串反向建,再FFT求卷积a*b,并计算a^2、b^2前缀和;
之后用a^2+b^2-2*ab=(a-b)^2即可求出不同位个数 复杂度为O(nlogn).
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int Maxn=2e5+5e4+50;
const int Maxm=Maxn*8;
const int INF=0x3f3f3f3f;
const double PI2=acos(-1.0)*2;
inline int read()
{
char ch=getchar();int i=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
return i*f;
}
struct complex
{
double r,i;
complex(double a=0,double b=0):r(a),i(b){}
friend inline complex operator +(const complex &a,const complex &b){return complex(a.r+b.r,a.i+b.i);}
friend inline complex operator -(const complex &a,const complex &b){return complex(a.r-b.r,a.i-b.i);}
friend inline complex operator *(const complex &a,const complex &b){return complex(a.r*b.r-a.i*b.i,a.i*b.r+a.r*b.i);}
inline complex conj(){return complex(r,-i);}
}A[Maxm],B[Maxm],C[Maxm];
struct FFT
{
int k,pos[Maxm];
inline void Init(int len)
{
for(k=1;k<=len;k<<=1);
k<<=1;
for(int i=1;i<=k;i++)
pos[i]=(i&1)?((pos[i>>1]>>1)^(k>>1)):(pos[i>>1]>>1);
}
inline void dft(complex *a,int dft)
{
for(int i=1;i<k;i++)
if(i<pos[i])swap(a[i],a[pos[i]]);
for(int m1=1,m2;m1<k;m1<<=1)
{
m2=m1<<1;
double temp=PI2/m2*(double)dft;
complex wn(cos(temp),sin(temp));
for(int i=0;i<k;i+=m2)
{
complex w(1,0);
for(int j=0;j<m1;j++)
{
complex &A=a[i+j],&B=a[i+j+m1],t=B*w;
B=A-t;A=A+t;w=w*wn;
}
}
}
}
inline void muitiply(complex *a,complex *b,complex *c)
{
dft(a,1),dft(b,1);
for(int i=0;i<k;i++)c[i]=a[i]*b[i];
dft(c,-1);
for(int i=0;i<k;i++)c[i].r/=(double)k;
}
}fft;
int n,m;
int a1[Maxn],a2[Maxn];
int b1[Maxn],b2[Maxn];
int nxt[Maxn],pos[Maxn],cnt,ans,maxn=INF;
inline void getnxt()
{
for(int i=2,j=0;i<=m;i++)
{
while(j&&b1[j+1]!=b1[i])j=nxt[j];
if(b1[j+1]==b1[i])j++;
nxt[i]=j;
}
}
inline void kmp()
{
getnxt();
for(int i=1,j=0;i<=n;i++)
{
while(j&&a1[i]!=b1[j+1])j=nxt[j];
if(a1[i]==b1[j+1])j++;
if(j==m)
{
pos[++cnt]=i-j+1;
j=nxt[j];
}
}
}
inline void calc()
{
fft.Init(n+m);
for(int i=1;i<=n;i++)A[i-1].r=a2[i];
for(int j=1;j<=m;j++)B[m-j].r=b2[j];
for(int i=1;i<=n;i++)a2[i]+=a2[i-1];
for(int i=1;i<=m;i++)b2[i]+=b2[i-1];
fft.muitiply(A,B,C);
for(int i=1;i<=cnt;i++)
{
int t=a2[pos[i]+m-1]-a2[pos[i]-1]+b2[m]-2*floor(C[pos[i]+m-2].r+0.5);
if(t<maxn)
{
ans=i,maxn=t;
}
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
a1[i]=read();
a2[i]=a1[i]%10;
a1[i]/=10;
}
for(int i=1;i<=m;i++)
{
b1[i]=read();
b2[i]=b1[i]%10;
b1[i]/=10;
}
kmp();
if(!cnt)puts("No");
else
{
puts("Yes");
calc();
printf("%d %d",maxn,pos[ans]);
}
}