LA6886 Golf Bot(FFT)
题目
Source
Description
Do you like golf? I hate it. I hate golf so much that I decided to build the ultimate golf robot, a robot that will never miss a shot. I simply place it over the ball, choose the right direction and distance and, flawlessly, it will strike the ball across the air and into the hole. Golf will never be played again.
Unfortunately, it doesn’t work as planned. So, here I am, standing in the green and preparing my first strike when I realize that the distance-selector knob built-in doesn’t have all the distance options! Not everything is lost, as I have 2 shots.
Given my current robot, how many holes will I be able to complete in 2 strokes or less? The ball must be always on the right line between the tee and the hole. It isn’t allowed to overstep it and come back.
Input
The input file contains several test cases, each of them as described below.
The first line has one integer: N, the number of different distances the Golf Bot can shoot. Each of the following N lines has one integer, ki , the distance marked in position i of the knob.
Next line has one integer: M, the number of holes in this course. Each of the following M lines has one integer, dj , the distance from Golf Bot to hole j.
Constraints:
1 ≤ N, M ≤ 200 000
1 ≤ ki
, dj ≤ 200 000
Output
For each test case, you should output a single integer, the number of holes Golf Bot will be able to complete. Golf Bot cannot shoot over a hole on purpose and then shoot backwards.
Sample Output Explanation
Golf Bot can shoot 3 different distances (1, 3 and 5) and there are 6 holes in this course at distances 2, 4, 5, 7, 8 and 9. Golf Bot will be able to put the ball in 4 of these:
• The 1st hole, at distance 2, can be reached by striking two times a distance of 1.
• The 2nd hole, at distance 4, can be reached by striking with strength 3 and then strength 1 (or vice-versa).
• The 3rd hole can be reached with just one stroke of strength 5.
• The 5th hole can be reached with two strikes of strengths 3 and 5.
Holes 4 and 6 can never be reached.
Sample Input
3
1
3
5
6
2
4
5
7
8
9
Sample Output
4
分析
题目大概说打高尔夫球,没打一次球球能滚的距离有n种情况,现在已知m个洞的位置,球只能往前打,最多能打两下,问有多少个洞能打进球。
构造两个多项式,指数表示距离,系数表示存不存在(1或0),然后用FFT相乘,结果各个系数就表示打2次打到对应指数距离的方案数,算是母函数的东西吧。。很简单的题。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 555555 const double PI=acos(-1.0); struct Complex{ double real,imag; Complex(double _real,double _imag):real(_real),imag(_imag){} Complex(){} Complex operator+(const Complex &cp) const{ return Complex(real+cp.real,imag+cp.imag); } Complex operator-(const Complex &cp) const{ return Complex(real-cp.real,imag-cp.imag); } Complex operator*(const Complex &cp) const{ return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag); } void setValue(double _real=0,double _imag=0){ real=_real; imag=_imag; } }; int len; Complex wn[MAXN],wn_anti[MAXN]; void FFT(Complex y[],int op){ 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; } for(int h=2; h<=len; h<<=1){ Complex Wn=(op==1?wn[h]:wn_anti[h]); for(int i=0; i<len; i+=h){ Complex W(1,0); for(int j=i; j<i+(h>>1); ++j){ Complex u=y[j],t=W*y[j+(h>>1)]; y[j]=u+t; y[j+(h>>1)]=u-t; W=W*Wn; } } } if(op==-1){ for(int i=0; i<len; ++i) y[i].real/=len; } } void Convolution(Complex A[],Complex B[],int n){ for(len=1; len<(n<<1); len<<=1); for(int i=n; i<len; ++i){ A[i].setValue(); B[i].setValue(); } FFT(A,1); FFT(B,1); for(int i=0; i<len; ++i){ A[i]=A[i]*B[i]; } FFT(A,-1); } bool vis[MAXN]; Complex A[MAXN],B[MAXN]; int main(){ for(int i=0; i<MAXN; ++i){ wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i)); wn_anti[i].setValue(wn[i].real,-wn[i].imag); } int n,m,a; while(scanf("%d",&n)==1){ memset(vis,0,sizeof(vis)); int mx=0; for(int i=0; i<n; ++i){ scanf("%d",&a); A[a].setValue(1); B[a].setValue(1); vis[a]=1; mx=max(mx,a); } Convolution(A,B,mx+1); for(int i=0; i<len; ++i){ int tmp=(int)(A[i].real+0.5); if(tmp) vis[i]=1; A[i].setValue(); B[i].setValue(); } int ans=0; scanf("%d",&m); for(int i=0; i<m; ++i){ scanf("%d",&a); if(vis[a]) ++ans; } printf("%d\n",ans); } return 0; }