題意:你有若干把斧頭,河神拿了你的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 }