题目链接: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回来。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const double PI = acos(-1.0); 5 typedef struct Complex { 6 double r,i; 7 Complex(double _r = 0.0,double _i = 0.0) { 8 r = _r; i = _i; 9 } 10 Complex operator +(const Complex &b) { 11 return Complex(r+b.r,i+b.i); 12 } 13 Complex operator -(const Complex &b) { 14 return Complex(r-b.r,i-b.i); 15 } 16 Complex operator *(const Complex &b) { 17 return Complex(r*b.r-i*b.i,r*b.i+i*b.r); 18 } 19 }Complex; 20 21 void change(Complex y[],int len) { 22 int i,j,k; 23 for(i = 1, j = len/2;i < len-1; i++) { 24 if(i < j)swap(y[i],y[j]); 25 k = len/2; 26 while( j >= k) { 27 j -= k; 28 k /= 2; 29 } 30 if(j < k) j += k; 31 } 32 } 33 34 void fft(Complex y[],int len,int on) { 35 change(y,len); 36 for(int h = 2; h <= len; h <<= 1) { 37 Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h)); 38 for(int j = 0;j < len;j+=h) { 39 Complex w(1,0); 40 for(int k = j;k < j+h/2;k++) { 41 Complex u = y[k]; 42 Complex t = w*y[k+h/2]; 43 y[k] = u+t; 44 y[k+h/2] = u-t; 45 w = w*wn; 46 } 47 } 48 } 49 if(on == -1) { 50 for(int i = 0;i < len;i++) { 51 y[i].r /= len; 52 } 53 } 54 } 55 56 const int maxn = 400040; 57 typedef long long LL; 58 int a[maxn]; 59 Complex c[maxn]; 60 LL f[maxn]; 61 int n, m; 62 63 int main() { 64 // freopen("in", "r", stdin); 65 int T; 66 scanf("%d", &T); 67 while(T--) { 68 memset(f, 0, sizeof(f)); 69 scanf("%d%d",&n,&m); 70 int maxx = -1; 71 for(int i = 0; i < n; i++) { 72 scanf("%d", &a[i]); 73 maxx = max(a[i], maxx); 74 f[a[i]]++; 75 } 76 int len1 = maxx + 1; 77 int len = 1; 78 while(len < 2 * len1) len <<= 1; 79 for(int i = 0; i < len; i++) c[i] = Complex(0, 0); 80 for(int i = 0; i < len1; i++) c[i] = Complex(f[i], 0); 81 fft(c, len, 1); 82 for(int i = 0; i < len; i++) c[i] = c[i] * c[i]; 83 fft(c, len, -1); 84 for(int i = 0; i < len; i++) f[i] = (LL)(c[i].r + 0.5); 85 len = 2 * maxx; 86 for(int i = 0; i < n; i++) f[a[i]*2]--; 87 for(int i = 1; i <= len; i++) { 88 f[i] /= 2; 89 f[i] += f[i-1]; 90 } 91 while(m--) { 92 int k; 93 scanf("%d", &k); 94 printf("%lld\n", f[k-1]); 95 } 96 } 97 return 0; 98 }
时间: 2024-10-08 02:14:57