bzoj3771 Triple

題意:你有若干把斧頭,河神拿了你的1/2/3把斧頭,問可能拿了你的斧頭的總價值,每一個總價值有多少種方案。ide

斧頭價值不大於40000函數

解:spa

很容易想到是FFT,構造函數以後A + A² + A3便可。code

而後發現漏洞百出,這道題的難點是在容斥上......blog

首先只選一個的不用管了,確定對。string

而後考慮選兩個的。你直接卷積,有可能把同一把斧頭選兩次,還會把一個方案的兩個不一樣排列當兩次計算。it

因此咱們先減去把統一斧頭選兩次的狀況,而後把結果 / 2就是選兩個的答案。io

選三個呢?咱們還要構造一個函數B,表明強制把某斧頭選兩次,剩下的隨便選。event

而後考慮選兩個一樣的斧頭的狀況:在A3中會被計算三次,由於排列有三種。在AB中會被計算一次。class

選三個一樣的狀況:在A3中有一次,在AB中有一次。

三個不一樣的狀況:在A3中有6次。在AB中沒有。

綜上,能夠用A3 - 3AB + 2*(每一個斧頭選三次) 便可。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <cmath>
  5 
  6 const int N = 250010;
  7 const double pi = 3.1415926535897932384626;
  8 
  9 struct cp {
 10     double x, y;
 11     cp(double X = 0, double Y = 0) {
 12         x = X;
 13         y = Y;
 14     }
 15     inline cp operator +(const cp &w) const {
 16         return cp(x + w.x, y + w.y);
 17     }
 18     inline cp operator -(const cp &w) const {
 19         return cp(x - w.x, y - w.y);
 20     }
 21     inline cp operator *(const cp &w) const {
 22         return cp(x * w.x - y * w.y, x * w.y + y * w.x);
 23     }
 24 }a[N], b[N], c[N];
 25 
 26 int r[N], val[N], ans[N], ans2[N];
 27 
 28 inline void FFT(int n, cp *a, int f) {
 29     for(int i = 0; i < n; i++) {
 30         if(i < r[i]) {
 31             std::swap(a[i], a[r[i]]);
 32         }
 33     }
 34     for(int len = 1; len < n; len <<= 1) {
 35         cp Wn(cos(pi / len), f * sin(pi / len));
 36         for(int i = 0; i < n; i += (len << 1)) {
 37             cp w(1, 0);
 38             for(int j = 0; j < len; j++) {
 39                 cp t = a[i + len + j] * w;
 40                 a[i + len + j] = a[i + j] - t;
 41                 a[i + j] = a[i + j] + t;
 42                 w = w * Wn;
 43             }
 44         }
 45     }
 46     if(f == -1) {
 47         for(int i = 0; i <= n; i++) {
 48             a[i].x /= n;
 49         }
 50     }
 51     return;
 52 }
 53 
 54 int main() {
 55     int n, mx = 0;
 56     scanf("%d", &n);
 57     for(int i = 1; i <= n; i++) {
 58         scanf("%d", &val[i]);
 59         a[val[i]].x += 1;
 60         b[val[i] << 1].x += 1;
 61         mx = std::max(mx, val[i]);
 62     }
 63     int len = 2, lm = 1;
 64     while(len <= mx * 3) {
 65         len <<= 1;
 66         lm++;
 67     }
 68     for(int i = 1; i <= len; i++) {
 69         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 70     }
 71 
 72     FFT(len, b, 1);
 73     FFT(len, a, 1);
 74     for(int i = 0; i <= len; i++) {
 75         c[i] = a[i] * b[i];
 76         b[i] = a[i] * a[i];
 77         a[i] = a[i] * b[i];
 78     }
 79     FFT(len, a, -1); // 取三個
 80     FFT(len, b, -1); // 取兩個
 81     FFT(len, c, -1); // 取三個,有兩個同樣
 82 
 83     for(int i = 0; i <= len; i++) {
 84         ans[i] += (int)(a[i].x + 0.5);
 85         ans[i] -= (int)(c[i].x + 0.5) * 3;
 86     }
 87     for(int i = 1; i <= n; i++) {
 88         ans[val[i] * 3] += 2;
 89         ans2[val[i] * 2]--;
 90     }
 91     for(int i = 0; i <= len; i++) {
 92         ans[i] /= 6;
 93         ans2[i] += (int)(b[i].x + 0.5);
 94         ans2[i] /= 2;
 95     }
 96 
 97     for(int i = 1; i <= n; i++) {
 98         ans[val[i]]++;
 99     }
100 
101     for(int i = 0; i <= len; i++) {
102         if(ans[i] + ans2[i]) {
103             printf("%d %d \n", i, ans[i] + ans2[i]);
104         }
105     }
106     return 0;
107 }
AC代碼
相關文章
相關標籤/搜索