Decription
给定一个物品集合,每个物品有一个价值。可以在其中使用 1,2,3 1 , 2 , 3 个物品,求凑成的物品总价值方案数。
n,ai⩽40000 n , a i ⩽ 40000
Solution
设 ai a i 表示取一个物品价值和为 i i 的方案数,分别为两个,三个物品的方案数。
对于每一个出现的价值,就在其对应的生成函数上的位置 +1 + 1 。
通过容斥不难得到以下式子
ans=∑ai+(ai×ai−bi)2+ai×ai×ai−bi×ai×3+ci×26 a n s = ∑ a i + ( a i × a i − b i ) 2 + a i × a i × a i − b i × a i × 3 + c i × 2 6
#include <bits/stdc++.h>
using namespace std;
const int maxn = 40005, maxm = 131075;
int n, maxa;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
typedef complex<double> cpx;
const double pi = acos(-1);
cpx a[maxm], b[maxm], c[maxm], ans[maxm];
int m, L, R[maxm];
void fft(cpx *a, int f)
{
for (int i = 0; i < m; ++i)
if (i < R[i]) swap(a[i], a[R[i]]);
for (int i = 1; i < m; i <<= 1) {
cpx wn(cos(pi / i), sin(f * pi / i)), t;
for (int j = 0; j < m; j += (i << 1)) {
cpx w(1, 0);
for (int k = 0; k < i; ++k, w *= wn) {
t = w * a[j + i + k];
a[j + i + k] = a[j + k] - t;
a[j + k] = a[j + k] + t;
}
}
}
}
int main()
{
n = gi();
for (int x, i = 1; i <= n; ++i) {
x = gi(); maxa = max(maxa, x);
a[x] = 1; b[x + x] = 1; c[x + x + x] = 1;
}
n = maxa * 3;
for (m = 1; m <= n; m <<= 1) ++L;
for (int i = 0; i < m; ++i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
fft(a, 1); fft(b, 1); fft(c, 1);
for (int i = 0; i < m; ++i) {
ans[i] += (a[i] * a[i] * a[i] - a[i] * b[i] * 3. + c[i] * 2.) / 6.;
ans[i] += (a[i] * a[i] - b[i]) / 2.;
ans[i] += a[i];
}
fft(ans, -1);
for (int i = 0; i < m; ++i) {
int x = (int)(ans[i].real() / m + 0.5);
if (x) printf("%d %d\n", i, x);
}
return 0;
}