题意:给n个数,m次询问,求和<k的数有多少对。
思路:先统计每个数各多少个,然后构造一个多项式,多项式的指数为每个数,系数为个数。然后用该多项式*该多项式,得到的新的多项式的指数就是任意一对数之和,系数就是和为指数的个数(当然有重复的,后面要去重,去重有两个情况,自己乘自己的部分要减去,还有任意一对都有两种可能所以还要除2),如何快速得到新的多项式,这里套入FFT模板解决。然后就用前缀和统计个数就能O(1)查询了。下面给代码:
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 270000;
typedef long long LL;
const int MOD=1e9+7;
const double pi=acos(-1);
struct cplx{
double r,i;
cplx(double r=0,double i=0):r(r),i(i){}
cplx operator +(const cplx &a)const
{return cplx(r+a.r,i+a.i);}
cplx operator -(const cplx &a)const{
return cplx(r-a.r,i-a.i);}
cplx operator *(const cplx &a)const
{return cplx(r*a.r-i*a.i,r*a.i+i*a.r);}
}f1[maxn*2],f2[maxn],res[maxn*2];
void rader(cplx *f,int len){
int j=len>>1;
for(int i=1;i<len-1;++i){
if(i<j)swap(f[i],f[j]);
int k=len>>1;
while(j>=k){
j-=k;
k>>=1;
}
if(j<k)j+=k;
}
}
void FFT(cplx *f,int len,int t){
rader(f,len);
for(int h=2;h<=len;h<<=1){
cplx wn(cos(-t*2*pi/h),sin(-t*2*pi/h));
for(int j=0;j<len;j+=h){
cplx e(1,0);
for(int k=j;k<j+h/2;++k){
cplx u=f[k];
cplx v=e*f[k+h/2];
f[k]=u+v;
f[k+h/2]=u-v;
e=e*wn;
}
}
}
if(t==-1)for(int i=0;i<len;i++)f[i].r/=len;
}
void Conv(cplx *a,cplx *b,int len){
FFT(a,len,1);
FFT(b,len,1);
for(int i=0;i<len;++i)a[i]=a[i]*b[i];
FFT(a,len,-1);
}
int cnt[maxn];
LL sum[maxn*2];
int main()
{
int n,k,t,T,m;
scanf("%d",&T);
while(T--)
{
memset(cnt,0,sizeof(cnt));
scanf("%d%d",&n,&m);
int maxx=0;
for(int i=0;i<n;i++)
{
scanf("%d",&t);
cnt[t]++;//cnt[t] shi x^t de xi shu
maxx=max(t,maxx);
}
// int len=log2(n);
// if(pow(2,len)<n) len++;
// len=pow(2,len);
// cout<<len<<endl;
int len=1;
while(len<=maxx) len<<=1;len<<=1;
for(int j=0;j<len;j++)
{
f1[j].r=f2[j].r=cnt[j];
f1[j].i=f2[j].i=0;
}
Conv(f1,f2,len);
/*for(int i=0;i<len;i++)
{
f1[i].r/=len;
f1[i].r+=1e-9;
}*/
/*for(int i=0;i<len;i++){
if(i==10)
break;
printf("%lf\n",f1[i].r);
}*/
for(int i=0;i<len;i++){
f1[i*2].r-=cnt[i];
if(i) sum[i]=sum[i-1]+(LL)(f1[i].r+0.5);
}
while(m--){
int x;
scanf("%d",&x);
printf("%lld\n",(sum[x-1])>>1);
}
}
}
本文介绍了一种利用FFT算法快速解决给定数组中数对求和小于特定值的问题的方法。通过统计数的出现次数并构造多项式,利用FFT进行多项式相乘,最后通过前缀和实现高效查询。

被折叠的 条评论
为什么被折叠?



