ural 1996
题解
- 只有最后一个数字可以修改,所以我们把最后一个单独那出来。比如A串单独拿出来为1 0 1 1 0 1,B串为1 0 0。那么对于第i个位置,我们可以计算从第i-m+1个位置开始至此,共有多少个01不匹配。上面这个为 1 1 1 3 1 1,记做res[N];
- 我们可以先计算A串为1,B串为0,有多少不匹配。再计算A串为0,B串为1有多少不匹配。再相加。
- 对于第一种情况,我们可以翻转B串的01,便得到0 1 1。我们可以先和1 0 1比较,发现最后一个对上了,所以结果为1。和0 1 1倒数两个对上了,所以结果为2。我们有更快捷的方法,反转0 1 1得到1 1 0。这样子1 0 1的最后一个1实际上和1 1 0的第一个要匹配。变成多项式就为(1 + 0^x1 + x^2)(1 + x + 0x^2)这样x^2的系数为1。同理第二个,(0 + x^1 + x^2)(1 + x^1 + 0),x^3的系数为2。用FFT可以快速处理。
- 最后把前7位拿出来进行KMP算法,匹配上的再比较res[N]。
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 250000 + 10;
int const inf = 0x7f7f7f7f;
double const pi = acos(-1.0);
int n,m,rev[N<<2],res[N<<2];
int s1[N],s2[N],ne[N];
struct Complex{
double x,y;
Complex(){}
Complex(double x,double y):x(x),y(y){}
Complex(double x):x(x),y(0.0){}
Complex operator + (const Complex &e) const{
return Complex(x + e.x,y + e.y);
}
Complex operator - (const Complex &e) const{
return Complex(x - e.x,y - e.y);
}
Complex operator * (const Complex &e) const{
return Complex(x * e.x- y * e.y,x * e.y + y * e.x);
}
Complex operator / (const Complex &e) const{
double m = e.x * e.x-e.y * e.y;
return Complex((x * e.x + y * e.y) / m,(y * e.x-x * e.y) / m);
}
}a[N<<2],b[N<<2];
void FFT(Complex *a,int n,int inv){
int bit = 0;
while((1<<bit)<n) bit++;
for(int i=0;i<n;i++){
rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i]) swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<n;mid*=2){
Complex temp(cos(pi/mid),inv*sin(pi/mid));
for(int i=0;i<n;i+=mid*2){
Complex omega(1,0);
for(int j=0;j<mid;j++,omega=omega*temp){
Complex x=a[i+j],y=omega * a[i+j+mid];
a[i+j] = x + y,a[i+j+mid] = x-y;
}
}
}
}
void Cacl(int x,int y){ //s1串为1,s2串为0的个数
int len;
for(len=1;len<=n+m;len<<=1);
for(int i=0;i<=len;i++){
if(i < n && (s1[i]&1) == x) a[i] = Complex(1,0);
else a[i] = Complex(0,0);
if(i < m && (s2[m-i-1]&1) == y) b[i] = Complex(1,0);
else b[i] = Complex(0,0);
}
FFT(a,len,1); FFT(b,len,1);
for(int i=0;i<=len;i++) a[i] = a[i] * b[i];
FFT(a,len,-1);
for(int i=0;i<=len;i++) res[i] += (int)(a[i].x / len + 0.5);
}
void get_ne(int s[N],int len){ //找前缀数组
memset(ne,0,sizeof(ne));
ne[0] = -1;
int i = 0,k = -1; //j从-1开始可以排除第一个数的干扰
while(i < len){
if(k == -1 || s[i] == s[k]) ne[++i] = ++k;
else k = ne[k];
}
}
void KMP(int p[N],int s[N],int len1,int len2){
int i = 0,j = 0,ans = inf,pos;
while(i < len1 && j < len2){
if(j == -1 || p[i] == s[j]) i++, j++;
else j = ne[j];
if(j == len2){
if(ans > res[i-1]){
ans = res[i-1];
pos = i - j + 1;
}
j = ne[j];
}
}
if(ans == inf) printf("No\n");
else{
printf("Yes\n");
printf("%d %d\n",ans,pos);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&s1[i]);
for(int i=0;i<m;i++) scanf("%d",&s2[i]);
Cacl(1,0);
Cacl(0,1);
for(int i=0;i<n;i++) s1[i] /= 10;
for(int i=0;i<m;i++) s2[i] /= 10;
get_ne(s2,m);
KMP(s1,s2,n,m);
}