FFT-hdu题目练习

网上FFT的讲解和板子有很多,所以直接放题目

 

hdu1402 http://acm.hdu.edu.cn/showproblem.php?pid=1402

 1 /*
 2 
 3 problem:大整数乘法
 4 
 5 solution:FFT
 6     两个n-1阶多项式的乘积表示为 a0*x^0 + a1*x^1 + ... + a(2n-2)*x^(2n-2)
 7     FFT可以O(nlogn)求出系数 a0, a1... a(2n-2)
 8     10进制整数x可以表示成 a0*10^0 + a1*10^1 + a2*10^2 + ...
 9     因此可以使用FFT求出其结果
10 
11 */
12 #include <bits/stdc++.h>
13 
14 using namespace std;
15 
16 const int maxn = 550010;
17 
18 const double pi = acos(-1.0);
19 
20 typedef complex<double> dob;
21 
22 int n, m, len1, len2, N, L, R[maxn], c[maxn];
23 
24 dob a[maxn], b[maxn];
25 
26 char s1[maxn], s2[maxn];
27 
28 void fft(dob *A, int f) {
29     for(int i = 0;i < n;i ++)
30         if(i < R[i])
31             swap(A[i], A[R[i]]);
32     for(int i = 1;i < n;i <<= 1) {
33         dob wn(cos(pi / i), sin(f * pi / i)), x, y;
34         for(int j = 0;j < n;j += (i << 1)) {
35             dob w(1, 0);
36             for(int k = 0;k < i;k ++, w *= wn) {
37                 x = A[j + k], y = w * A[i + j + k];
38                 A[j + k] = x + y;
39                 A[i + j + k] = x - y;
40             }
41         }
42     }
43 }
44 
45 int main() {
46     while(~scanf("%s %s", s1, s2)) {
47         len1 = n = strlen(s1);
48         len2 = m = strlen(s2);
49         m += n, L = 0;
50         for(n = 1;n <= m;n <<= 1) L ++;
51         for(int i = 0;i < len1;i ++)
52             a[i] = s1[len1 - 1 - i] - '0';
53         for(int i = len1;i < n;i ++)
54             a[i] = 0;
55         for(int i = 0;i < len2;i ++)
56             b[i] = s2[len2 - 1 - i] - '0';
57         for(int i = len2;i < n;i ++)
58             b[i] = 0;
59         memset(c, 0, sizeof c);
60         for(int i = 0;i < n;i ++)
61             R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
62         fft(a, 1), fft(b, 1);
63         for(int i = 0;i <= n;i ++)
64             a[i] *= b[i];
65         fft(a, -1), N = 0;
66         for(int i = 0;i <= m;i ++) {
67             c[i] += int(a[i].real() / n + 0.5);
68             if(c[i] > 9) c[i + 1] += c[i] / 10, c[i] %= 10;
69             if(c[i] > 0) N = i;
70         }
71         for(int i = N;~i;i --)
72             printf("%d", c[i]);
73         puts("");
74     }
75     return 0;
76 }

 

hdu4609 http://acm.hdu.edu.cn/showproblem.php?pid=4609

 1 /*
 2 
 3 problem:给定n个长度为ai的木棍
 4     求,任选三个使其能够组成三角形的概率
 5 
 6 solution:
 7     ai <= 1e5,先统计c[i]代表长度为i的木棍有多少个
 8     对c做卷积,即使用FFT求出 rep(i,0,1e5) rep(j,0,1e5) d[i+j]+=c[i]*c[j] 的d数组
 9     d[i]即代表选出两个木棍长度之和为i的方案数
10     去除重复,减去使用了同一木棍两次的,i+j与j+i应为同一方案,所以rep(i,0,2e5) d[i]/=2
11     现在d[i]已经可以表示选出两个不同木棍长度之和为i的不同方案数了
12 
13     接下来对木棍长度ai从小到大排序,对d做前缀和sd
14     枚举最长边为第i根木棍,则另外两条边长度之和>ai,ans+=sd[2e5]-sd[ai]
15     这些方案里需要去除一些不满足要求(ai为最长边)的
16     1.另外两条边两条均>ai,ans-=(n-i)*(n-i-1)/2
17     2.另外两条边一条>ai,一条<ai,ans-=(n-i)*(i-1)
18     3.另外两条边一条=ai,另一条随意,ans-=n-1
19 
20 */
21 #include <bits/stdc++.h>
22 
23 using namespace std;
24 
25 const int maxn = 300010;
26 
27 const double pi = acos(-1.0);
28 
29 typedef long long ll;
30 
31 typedef complex<double> dob;
32 
33 int T, N, n, r, L, R[maxn], X[maxn];
34 
35 dob a[maxn];
36 
37 ll ans, b[maxn];
38 
39 void fft(dob *A, int f) {
40     for(int i = 0;i < N;i ++)
41         if(i < R[i])
42             swap(A[i], A[R[i]]);
43     for(int i = 1;i < N;i <<= 1) {
44         dob wn(cos(pi / i), sin(f * pi / i)), x, y;
45         for(int j = 0;j < N;j += (i << 1)) {
46             dob w(1, 0);
47             for(int k = 0;k < i;k ++, w *= wn) {
48                 x = A[j + k], y = w * A[i + j + k];
49                 A[j + k] = x + y;
50                 A[i + j + k] = x - y;
51             }
52         }
53     }
54 }
55 
56 int main() {
57     for(scanf("%d", &T);T --;) {
58         scanf("%d", &n), ans = r = L = 0;
59         memset(b, 0, sizeof b);
60         for(int i = 1;i <= n;i ++) {
61             scanf("%d", &X[i]);
62             r = max(r, X[i]);
63             b[X[i]] ++;
64         }
65         for(N = 1;N <= (r + 1) * 2;N <<= 1) L ++;
66         for(int i = 0;i < N;i ++) a[i] = b[i];
67         for(int i = 0;i < N;i ++)
68             R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
69         fft(a, 1);
70         for(int i = 0;i < N;i ++)
71             a[i] *= a[i];
72         fft(a, -1);
73         for(int i = 0;i < N;i ++)
74             b[i] = ll(a[i].real() / N + 0.5);
75         for(int i = 1;i <= n;i ++)
76             b[X[i] * 2] --;
77         for(int i = 0;i < N;i ++)
78             b[i] >>= 1;
79         for(int i = 1;i < N;i ++)
80             b[i] += b[i - 1];
81         sort(X + 1, X + n + 1), b[N] = b[N - 1];
82         for(int i = 1;i <= n;i ++) {
83             ans += b[N] - b[X[i]];
84             ans -= 1ll * (i - 1) * (n - i);
85             ans -= (n - 1);
86             ans -= 1ll * (n - i) * (n - i - 1) / 2;
87         }
88         printf("%.7f\n", 1.0 * ans / (1ll * n * (n - 1) * (n - 2) / 6));
89     }
90     return 0;
91 }

 

hdu5885 http://acm.hdu.edu.cn/showproblem.php?pid=5885

 1 /*
 2 
 3 problem:
 4     n*m的矩形,每个点有p(i,j)
 5     你可以选择一个点(x,y),那么在该点可以得到的价值val为
 6     rep(i,1,n) rep(j,1,m) {
 7         dis=(i,j)与(x,y)欧几里得距离
 8         if(dis<R) val+=p(i,j)/(dis+1)
 9     }
10     要求选取一个点,使val最大,输出val
11 
12 solution:
13     利用圆的中心对称性,使FFT之后某个点的val都在一个系数上
14     最终构造得到的多项式系数 M=m+R*2
15     A[i*M+j]=p[i][j]  B[(i+R)*M+j+R]=1.0/(sqrt(i*i+j*j)+1)
16     val[i][j]=C[(i+R)*M+j+R]
17 
18     附:这题内存限制不大,建议A,B变换完成之后,令A*=B即可,舍去C数组防止MLE
19 
20 */
21 #include <bits/stdc++.h>
22 
23 using namespace std;
24 
25 typedef long long ll;
26 
27 namespace FFT {
28     const int maxn = 2100000;
29     //maxn >= (1 << k) >= n + m
30     const double pi = acos(-1.0);
31     
32     typedef complex<double> dob;
33     
34     int N_, L, R[maxn];
35     
36     dob a[maxn], b[maxn];
37     
38     void fft(dob *A, int f) {
39         for(int i = 0;i < N_;i ++) 
40             if(i < R[i])
41                 swap(A[i], A[R[i]]);
42         for(int i = 1;i < N_;i <<= 1) {
43             dob wn(cos(pi / i), sin(f * pi / i)), x, y;
44             for(int j = 0;j < N_;j += (i << 1)) {
45                 dob w(1, 0);
46                 for(int k = 0;k < i;k ++, w *= wn) {
47                     x = A[j + k], y = w * A[i + j + k];
48                     A[j + k] = x + y;
49                     A[i + j + k] = x - y;
50                 } 
51             }
52         }
53     }
54     
55     void solve(int n, int m) {
56         n += m;
57         for(N_ = 1;N_ <= n;N_ <<= 1) L ++;
58         for(int i = 0;i < N_;i ++)
59             R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
60         fft(a, 1), fft(b, 1);
61         for(int i = 0;i < N_;i ++)
62             a[i] *= b[i];
63         fft(a, -1);
64     }
65     
66     void clean() {
67         for(int i = 0;i < N_;i ++)
68             a[i] = b[i] = 0;
69         L = 0;
70     }
71 }
72 
73 using namespace FFT;
74 
75 int n, m, N, M, rr;
76 
77 double r;
78 
79 int main() {
80     double x, ans;
81     while(~scanf("%d %d %lf", &n, &m, &r)) {
82         rr = r, N = n + rr * 2, M = m + rr * 2, ans = 0;
83         for(int i = 0;i < n;i ++)
84             for(int j = 0;j < m;j ++) 
85                 scanf("%lf", &a[i * M + j]);
86         for(int i = -rr;i <= rr;i ++)
87             for(int j = -rr;j <= rr;j ++) {
88                 x = sqrt(i * i + j * j);
89                 if(r > x) b[(i + rr) * M + j + rr] = 1.0 / (x + 1);
90             }
91         solve(N * M, N * M);
92         for(int i = 0;i < n;i ++)
93             for(int j = 0;j < m;j ++) 
94                 ans = max(ans, a[(i + rr) * M + j + rr].real() / N_);
95         printf("%.3f\n", ans);
96         clean();
97     }
98     return 0;
99 }

 

持续更新

posted @ 2017-08-09 11:24  ztztyyy  阅读(1502)  评论(0编辑  收藏  举报