UVA12879 Golf Bot
UVA12879 Golf Bot
给定n个数 ai 和 m个数 bi
问ai+aj=bk的组数
Solution
暴力很好想, \(O(n^{2})\) 枚举ai
FFT可以让我们在 \(nlogn\) 的时间把多项式相乘
同底的数相乘,指数相加
所以我们把出现过的那一项的系数设为非零, 自己相乘, 得到的非零项就是加出来的数
然后观察下数据不用离散化
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
using namespace std;
const int MAXN=1e7+10;
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
const double Pi=acos(-1.0);
struct complex
{
double x,y;
complex (double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}//不懂的看复数的运算那部分
int N,M;
int l,r[MAXN];
int limit=1;
void FFT(complex *A,int type)
{
for(int i=0;i<limit;i++)
if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列
for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
{
complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根
for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了
{
complex w(1,0);//幂
for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分
{
complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
}
}
int MAX;
void init(){
REP(i, 0, MAXN - 1)a[i].x = a[i].y = r[i] = 0;
limit = 1, l = 0, MAX = 0;
}
void work(){
a[0].x = 1;
REP(i, 1, N){
int Index = RD();
a[Index].x = 1;
MAX = max(MAX, Index);
}
while(limit <= MAX + MAX)limit <<= 1, l++;
REP(i, 0, limit - 1) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
FFT(a, 1);
REP(i, 0, limit - 1)a[i] = a[i] * a[i];
FFT(a, -1);
M = RD();
int ans = 0;
REP(i, 1, M){
int ask = RD();
if((int)(a[ask].x / limit + 0.5))ans++;
}
cout<<ans<<endl;
}
int main(){
while(~scanf("%d", &N)){
init();
work();
}
return 0;
}