UVALive6886 Golf Bot[FFT]

M - Golf Bot

  UVALive - 6886 

Do you like golf? I hate it. I hate golf so much that I decided tobuild the ultimate golf robot, a robot that will never miss a shot. I simplyplace 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 willnever be played again.

Unfortunately, it doesn’t work as planned. So, here I am, standingin the green and preparing my first strike when I realize that thedistance-selector knob built-in doesn’t have all the distance options! Noteverything is lost, as I have 2 shots.

Given my currentrobot, how many holes will I be able to complete in 2 strokes or less? The ballmust be always on the right line between the tee and the hole. It isn’t allowedto overstep it and come back.

Input

The input file contains several testcases, each of them as described below.

The first line has oneinteger: N, the number of differentdistances the Golf Bot can shoot. Each of the followingNlines has one integer,ki,the distance marked in positioniofthe knob.

Next line has one integer: M,the number of holes in this course. Each of the followingMlines has one integer,dj,the distance from Golf Bot to holej.

Constraints:

1 ≤ N,M≤ 200000

1 ≤ ki,dj≤ 200000

Output

For each testcase, you should output a single integer, the number of holes Golf Bot will beable to complete. Golf Bot cannot shoot over a hole on purpose and then shootbackwards.

Sample Output Explanation

Golf Bot can shoot 3different distances (1, 3 and 5) and there are 6 holes in this course atdistances 2, 4, 5, 7, 8 and 9. Golf Bot will be able to put the ball in 4 ofthese:

•   The 1st hole, at distance 2, can be reached by striking twotimes a distance of 1.

•   The 2nd hole, at distance 4, can be reached by striking withstrength 3 and then strength 1 (or vice-versa).

•   The 3rd hole can be reached with just one stroke of strength5.

•   The 5th hole can be reached with two strikes of strengths 3and 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,接下来给出n个数,再给一个m,询问m中有多少个数能由1个或者2个所给的n个数中的数构成。(可重复使用)


题解:

FFT入门题。

可以题目所给的k不超过2e5,那么我们就可以把他列为多项式。

例如样例  可以列为 
那么他两两组合(包括自身跟自身组合)就是

运用FFT算出多项式乘积的结果。

那么我们就可以得出

当然,这只是两两组合的结果(这个多项式的结果是按组合顺序的,所以会重复计算了不同的两项组合的次数)

那么如果D[i]中有等于K[j]的,同样符合结果。

所以多项式上加上

再去判断共有多少个D[i]能被组合出来。


为了学FFT 去看了一些博客。

如果有兴趣的 可以去看看(T_T虽然我看了好久才看懂)

http://www.gatevin.moe/acm/fft%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

https://oi.men.ci/fft-notes/


#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int M=1<<20;
const double PI=acos(-1.0);
int K[N],D[N],num[N];
ll ans[M];
struct Complex
{
    double real,image;
    Complex(double r=0.0,double i=0.0):real(r),image(i){};
    Complex operator + (const Complex &b)
    {
        return Complex(real+b.real,image+b.image);
    }
    Complex operator - (const Complex &b)
    {
        return Complex(real-b.real,image-b.image);
    }
    Complex operator * (const Complex &b)
    {
        return Complex(real*b.real-image*b.image,image*b.real+real*b.image);
    }
}x[M];
void change(Complex x[],int len)
{
    for (int i=1,j=len/2 ; i<len-1 ; ++i)
    {
        if (i<j)
            swap(x[i],x[j]);
        int k=len/2;
        while (j>=k)
        {
            j-=k;
            k/=2;
        }
        if (j<k)
            j+=k;
    }
}
void FFT(Complex x[],int len,int dft)
{
    change(x,len);
    for (int h=2 ; h<=len ; h<<=1)
    {
        Complex wn(cos(dft*2*PI/h),sin(dft*2*PI/h));
        for (int j=0 ; j<len ; j+=h)
        {
            Complex w(1,0);
            for (int k=j ; k<j+h/2 ; ++k)
            {
                Complex u=x[k];
                Complex t=w*x[k+h/2];
                x[k]=u+t;
                x[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if (dft==-1)
    {
        for (int i=0 ; i<len ; ++i)
        {
            x[i].real/=len;
            x[i].image/=len;
        }
    }
}
int main()
{
	int n,m;
	while (~scanf("%d",&n))
    {
        int mx=0;
        memset(num,0,sizeof(num));
        for (int i=0 ; i<n ; ++i)
        {
            scanf("%d",&K[i]);
            num[K[i]]++;
            mx=max(mx,K[i]);
        }
        scanf("%d",&m);
        for (int i=0 ; i<m ; ++i)
            scanf("%d",&D[i]);
        int len=1;
        mx+=1;
        while (len<mx*2)
            len<<=1;

        for (int i=0 ; i<len ; ++i)
        {
            if (i<mx)
                x[i]=Complex(num[i],0);
            else
                x[i]=Complex(0,0);
        }
        FFT(x,len,1);
        for (int i=0 ; i<len ; ++i)
            x[i]=x[i]*x[i];
        FFT(x,len,-1);
        for (int i=0 ; i<len ; ++i)
            ans[i]=(ll)(x[i].real+0.5);
        for (int i=0 ; i<n ; ++i)
            ans[K[i]]++;
        ll res=0;
        for (int i=0 ; i<m ; ++i)
            if (D[i]<len && ans[D[i]])
                res++;
        printf("%lld\n",res);
    }
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值