AT_abc291_g [ABC291G] OR Sum 题解
AT_abc291_g [ABC291G] OR Sum 题解
一看到字符串匹配问题,就不由得想到了 FFT。
题目要求的其实是这个东西:
由于多位的按位或不能变为加减乘除的形式,所以考虑拆位;又因为
拆位,得:
又因为
令
我们发现:
是定值,值为
又因为多项式乘法中,
令
此时,
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn = (1 << 22) + 10;//要开到这,不然可能会RE
const double pi = acos(-1);//反三角函数
struct z{
double a,b;
z operator + (z other)
{
return {this -> a + other.a,this -> b + other.b};
}
z operator - (z other)
{
return {this -> a - other.a,this -> b - other.b};
}
z operator * (z other)
{
return {this -> a * other.a - this -> b * other.b,this -> a * other.b + this -> b * other.a};
}//重载运算符
}A[maxn][5],B[maxn][5],B_[maxn][5],B__[maxn][5],H[maxn][5];//一个下划线代表一个',例如B_就是前面推导过程中的B'
int n,a[maxn],b[maxn],sum,ans,maxx = 0,len = 1;
void FFT(z f[maxn][5],int l,int op,int j)
{
if(l == 1) return ;//判边界
z A0[l >> 1][5],A1[l >> 1][5];
for(int i = 0;i < l;i++)//奇偶拆分
{
if(i & 1) A1[i >> 1][j] = f[i][j];
else A0[i >> 1][j] = f[i][j];
}
FFT(A0,l >> 1,op,j);
FFT(A1,l >> 1,op,j);//递归
z w = {1,0},wk = {cos(2.0 * pi / l),op * sin(2.0 * pi / l)};//不要忘记乘op
for(int i = 0;i < (l >> 1);i++,w = w * wk)
{
f[i][j] = A0[i][j] + w * A1[i][j];
f[i + (l >> 1)][j] = A0[i][j] - w * A1[i][j];//O1赋值另一半
}
return ;
}
int main()
{
cin >> n;
for(int i = 0;i < n;i++)
{
cin >> a[i];
}
for(int i = n;i < 2 * n;i++)
{
a[i] = a[i - n];
}
for(int i = 0;i < 2 * n;i++)
{
A[i][0].a = a[i] % 2;
a[i] >>= 1;
A[i][1].a = a[i] % 2;
a[i] >>= 1;
A[i][2].a = a[i] % 2;
a[i] >>= 1;
A[i][3].a = a[i] % 2;
a[i] >>= 1;
A[i][4].a = a[i] % 2;
}
for(int i = 0;i < n;i++)
{
cin >> b[i];
B[i][0].a = b[i] % 2;
sum += B[i][0].a;
b[i] >>= 1;
B[i][1].a = b[i] % 2;
sum += ((int)(B[i][1].a + 0.5) << 1);
b[i] >>= 1;
B[i][2].a = b[i] % 2;
sum += ((int)(B[i][2].a + 0.5) << 2);
b[i] >>= 1;
B[i][3].a = b[i] % 2;
sum += ((int)(B[i][3].a + 0.5) << 3);
b[i] >>= 1;
B[i][4].a = b[i] % 2;
sum += ((int)(B[i][4].a + 0.5) << 4);
}
for(int i = 0;i < n;i++)
{
for(int j = 0;j < 5;j++)
{
B_[i][j].a = 1 - B[i][j].a;
}
}
for(int i = 0;i < n;i++)
{
for(int j = 0;j < 5;j++)
{
B__[i][j].a = B_[n - i - 1][j].a;
}
}
while(len <= 3 * n - 1) len <<= 1;
//以上为初始化
for(int i = 0;i < 5;i++)
{
FFT(A,len,1,i);
FFT(B__,len,1,i);//求单位根点值
}
for(int i = 0;i < len;i++)
{
for(int j = 0;j < 5;j++)
{
H[i][j] = A[i][j] * B__[i][j];
}
}
for(int i = 0;i < 5;i++) FFT(H,len,-1,i);//逆运算
for(int i = 0;i < len;i++)
{
for(int j = 0;j < 5;j++)
{
H[i][j].a = ((int)(H[i][j].a / len + 0.5)) * (1 << j);//千万不要忘了乘(1 << j),拆位之后还要合并
}
}
for(int k = 0;k < n;k++)
{
ans = 0;
for(int j = 0;j < 5;j++)
{
ans += (H[n + k - 1][j].a + 0.5);
}
maxx = max(maxx,ans);//求值
}
cout << maxx + sum << '\n';//又切一道紫
return 0;
}