cf E. Thief in a Shop - fft + 多項式快速冪 + 母函式
阿新 • • 發佈:2021-01-07
傳送門
其實是個假的多項式快速冪
在\(n\)種物品裡,選擇\(k\)個物品,然後看有幾種權值和有哪些
就是母函式模板吧,然後k次多項式乘法,而且是對於一個多項式來說,那就進行多項式快速冪。同時用fft維護,(真多項式快速冪應該不是這麼簡單)
如果說用ntt的話,要用雙膜去求,因為只取一個膜會被使得多項式的值變成0的。其實我感覺就不能取模,所以還是fft維護比較好
#include <cstdio> #include <iostream> #include <cmath> using namespace std; const int N = 3e6 + 5; // 剛好比n大的2的k次方再乘2 struct Complex{ double x, y; Complex(double x = 0, double y = 0):x(x),y(y){}; inline Complex operator + (const Complex b) const { return Complex(x + b.x,y + b.y); } inline Complex operator - (const Complex b) const { return Complex(x - b.x,y - b.y); } inline Complex operator * (const Complex b) const { return Complex(x * b.x - y * b.y, x * b.y + y * b.x); } }; namespace FFT{ const double Pi = acos(-1); const int N = 3e6 + 5; // 剛好比n大的2的k次方再乘2 Complex F[N], G[N]; int r[N], n, m; void FFT(Complex *a, int n, int inv){ for(int i = 0; i < n; i++) if(r[i] > i) swap(a[r[i]], a[i]); for(int mid = 2; mid <= n; mid <<= 1){ Complex x(cos(2 * Pi / mid), inv * sin(2 * Pi / mid)); for(int i = 0; i < n; i += mid){ Complex w(1,0); for(int j = i; j < i + (mid >> 1); j++, w = w * x){ Complex t1 = a[j],t2 = a[j + (mid >> 1)] * w; a[j] = t1 + t2; a[j + (mid >> 1)] = t1 - t2; } } } } void mul(int *a, int *b, int *c, int nn, int mm, int &k) { n = nn, m = mm; for(mm += nn, nn = 1; nn <= mm; nn *= 2); for(int i = 0; i <= nn; i++) F[i].x = F[i].y = G[i].x = G[i].y = 0; for(int i = 0; i <= n; i++) F[i].x = a[i]; for(int i = 0; i <= m; i++) G[i].x = b[i]; int l = 0; for(m += n, n = 1; n <= m; n *= 2, l++); for(int i = 0; i < n; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1)); FFT(F, n, 1); FFT(G, n, 1); for(int i = 0; i < n; i++) F[i] = F[i] * G[i]; FFT(F, n, -1); k = m; for(int i = 0; i <= m; i++) { int x = int(F[i].x / n + 0.5); c[i] = x ? 1 : 0; } } } int a[N], b[N], ans[N]; int quick(int *a, int n, int k) { ans[0] = 1; int nu1 = n, nu2 = n; for(int i = 0; i <= n; i++) b[i] = a[i]; while(k){ if(k & 1) FFT::mul(ans, a, ans, nu1, nu2, nu1); FFT::mul(a, a, a, nu2, nu2, nu2); k >>= 1; } for(int i = 0; i <= nu1; i++) a[i] = ans[i]; return nu1; } int main(){ int n, m = 0, k; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); a[x] = 1; m = max(m, x); } int num = quick(a, m, k); for(int i = 0; i <= num; i++) if(a[i]) printf("%d ", i); return 0; }