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;
	}
原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/14657242.html