SPOJ SWERC14C Golf Bot

本文深入浅出地讲解了FFT算法的基本原理,并通过一个具体的实战案例进行演示。介绍了如何利用FFT算法解决多项式乘法问题,包括算法的核心思想、代码实现细节及优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

http://www.spoj.com/problems/SWERC14C/

思路

FFT半裸题了。
如果一个多项式有 xi x i 项,另一个多项式有 xj x j 项,那么相乘后的多项式就一定有 xi+j x i + j 项。
那么如果读入一个数 i i ,那么多项式xi项就赋值为 1 1
最后把多项式平方,得出多项式次数为哪些时,系数有值,说明这个次数能被凑出来。

代码

#include <cstdio>
#include <cmath>
#include <algorithm>

const int maxn=200000;
const double pi=acos(-1);

struct complex
{
  double r,i;

  complex(double r_=0,double i_=0)
  {
    r=r_;
    i=i_;
  }

  complex operator +(const complex &other) const
  {
    return complex(r+other.r,i+other.i);
  }

  complex operator -(const complex &other) const
  {
    return complex(r-other.r,i-other.i);
  }

  complex operator *(const complex &other) const
  {
    return complex(r*other.r-i*other.i,r*other.i+i*other.r);
  }
};

complex a[maxn<<2];
int rev[maxn<<2],n,m,ans;

int fft(complex* ar,int len,int op)
{
  for(register int i=0; i<len; ++i)
    {
      if(rev[i]<i)
        {
          std::swap(ar[rev[i]],ar[i]);
        }
    }
  for(register int i=2; i<=len; i<<=1)
    {
      complex wn(cos(2*pi/i),sin(2*pi*op/i));
      for(register int j=0; j<len; j+=i)
        {
          complex w(1,0);
          for(register int k=0; k<(i>>1); ++k)
            {
              complex x=ar[j+k],y=w*ar[j+k+(i>>1)];
              ar[j+k]=x+y;
              ar[j+k+(i>>1)]=x-y;
              w=w*wn;
            }
        }
    }
  if(op==-1)
    {
      for(register int i=0; i<len; ++i)
        {
          ar[i].r/=len;
        }
    }
  return 0;
}

inline int calc(int x)
{
  int l=0;
  m=1;
  while(m<=x)
    {
      m<<=1;
      ++l;
    }
  for(register int i=0; i<m; ++i)
    {
      rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    }
  return 0;
}

int main()
{
  scanf("%d",&n);
  for(register int i=1; i<=n; ++i)
    {
      int w;
      scanf("%d",&w);
      a[w].r=1;
    }
  a[0]=1;
  calc(maxn<<1);
  fft(a,m,1);
  for(register int i=0; i<m; ++i)
    {
      a[i]=a[i]*a[i];
    }
  fft(a,m,-1);
  scanf("%d",&n);
  for(register int i=1; i<=n; ++i)
    {
      int w;
      scanf("%d",&w);
      if(a[w].r-0.5>0)
        {
          ++ans;
        }
    }
  printf("%d\n",ans);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值