傳送門:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=77958#problem/C
題型:數論
題意:
集合A中取1個數或者2個數,其和變成一個新的集合S。q次查詢,每次查詢輸入一個數,問q個數中有多少個數屬於集合S。
集合A元素個數2e5,q<=2e5,A元素大小<=2e5,查詢數字2e5
分析:
暴力枚舉O(C(n,2)+n),O(n^2)複雜度過高。
FFT統計出現了哪些數,然後直接算結果就ok,複雜度O(nlogn)。
只取1個數只需要O(n)標記一下,S1 = {1,3,5}。
下面討論取2個數的情況:
例如A = {1,3,5}
設多項式
則S2 = {2,4,6,8,10}
綜上:S={1,2,3,4,5,6,8,10}
代碼;
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define mt(a,b) memset(a,b,sizeof(a))using namespace std;const int M = 201000;struct Complex { double x,y; Complex(double _x=0,double _y=0) { x=_x; y=_y; } friend Complex operator -(const Complex &a,const Complex &b) { return Complex(a.x-b.x,a.y-b.y); } friend Complex operator +(const Complex &a,const Complex &b) { return Complex(a.x+b.x,a.y+b.y); } friend Complex operator *(const Complex &a,const Complex &b) { return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }};class FFT { Complex u,t; void change(Complex y[],int len) { for(int i=1,j=len>>1,k; i<len-1; i++) { if(i<j) swap(y[i],y[j]); k=len>>1; while(j>=k) { j-=k; k>>=1; } if(j<k) j+=k; } }public: void fft(Complex y[],int len,int on) { change(y,len); double tmp=-on*2*acos(-1.0); for(int h=2; h<=len; h<<=1) { Complex wn(cos(tmp/h),sin(tmp/h)); for(int j=0; j<len; j+=h) { Complex w(1,0); int h2=h>>1; for(int k=j; k<j+h2; k++) { u=y[k]; t=w*y[k+h2]; y[k]=u+t; y[k+h2]=u-t; w=w*wn; } } } if(on==-1) { for(int i=0; i<len; i++) { y[i].x/=len; } } }} g;int flag[M*4];Complex x[M*4];int a[M*2];int main() { int n,q; while(~scanf("%d",&n)) { mt(flag,0); int maxn = 0; for(int i=0; i<n; i++) { scanf("%d",&a[i]); flag[a[i]] = 1; maxn = max(maxn,a[i]); } int len = 1; maxn<<=1; while(len<maxn) len<<=1; for(int i=0; i<len; i++) { x[i] = Complex(flag[i],0); } g.fft(x,len,1); for(int i=0;i<len;i++){ x[i] = x[i]*x[i]; } g.fft(x,len,-1); mt(flag,0); for(int i=0;i<n;i++){ flag[a[i]]++; } for(int i=0;i<len;i++){ flag[i] += (int)(x[i].x+0.5); }// for(int i=0;i<len;i++){// printf("%d--->%d\n",i,flag[i]);// } scanf("%d",&q); int b; int ans = 0; while(q--){ scanf("%d",&b); if(flag[b]) ans++; } printf("%d\n",ans); } return 0;}/**31356245789*/