[HRBUSTOJ1476]Pairs(FFT)

时间:2023-03-08 23:58:21
[HRBUSTOJ1476]Pairs(FFT)

题目链接:http://acm-software.hrbust.edu.cn/problem.php?id=1476

题意:给n个数,m次询问,每次询问一个k。问n个数里两数之和严格小于k的数对。

根据输入样例,无非是需要求:

f = cnt(1 2 3 4 5)T * (x)(其中(x)代表1,x,x^2...的向量,cnt表示这些数出现的次数,T表示转置)自乘一次后对应x幂次前的系数,取前k-1项系数和就是答案。复杂度太高了,O(n^2)的系数搞法是不可以的,所以需要搞成点值表达DFT后再IDFT回来。

 #include <bits/stdc++.h>
using namespace std; const double PI = acos(-1.0);
typedef struct Complex {
double r,i;
Complex(double _r = 0.0,double _i = 0.0) {
r = _r; i = _i;
}
Complex operator +(const Complex &b) {
return Complex(r+b.r,i+b.i);
}
Complex operator -(const Complex &b) {
return Complex(r-b.r,i-b.i);
}
Complex operator *(const Complex &b) {
return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
}
}Complex; void change(Complex y[],int len) {
int i,j,k;
for(i = , j = len/;i < len-; i++) {
if(i < j)swap(y[i],y[j]);
k = len/;
while( j >= k) {
j -= k;
k /= ;
}
if(j < k) j += k;
}
} void fft(Complex y[],int len,int on) {
change(y,len);
for(int h = ; h <= len; h <<= ) {
Complex wn(cos(-on**PI/h),sin(-on**PI/h));
for(int j = ;j < len;j+=h) {
Complex w(,);
for(int k = j;k < j+h/;k++) {
Complex u = y[k];
Complex t = w*y[k+h/];
y[k] = u+t;
y[k+h/] = u-t;
w = w*wn;
}
}
}
if(on == -) {
for(int i = ;i < len;i++) {
y[i].r /= len;
}
}
} const int maxn = ;
typedef long long LL;
int a[maxn];
Complex c[maxn];
LL f[maxn];
int n, m; int main() {
// freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
memset(f, , sizeof(f));
scanf("%d%d",&n,&m);
int maxx = -;
for(int i = ; i < n; i++) {
scanf("%d", &a[i]);
maxx = max(a[i], maxx);
f[a[i]]++;
}
int len1 = maxx + ;
int len = ;
while(len < * len1) len <<= ;
for(int i = ; i < len; i++) c[i] = Complex(, );
for(int i = ; i < len1; i++) c[i] = Complex(f[i], );
fft(c, len, );
for(int i = ; i < len; i++) c[i] = c[i] * c[i];
fft(c, len, -);
for(int i = ; i < len; i++) f[i] = (LL)(c[i].r + 0.5);
len = * maxx;
for(int i = ; i < n; i++) f[a[i]*]--;
for(int i = ; i <= len; i++) {
f[i] /= ;
f[i] += f[i-];
}
while(m--) {
int k;
scanf("%d", &k);
printf("%lld\n", f[k-]);
}
}
return ;
}