1. 程式人生 > 實用技巧 >cf E. Thief in a Shop - fft + 多項式快速冪 + 母函式

cf E. Thief in a Shop - fft + 多項式快速冪 + 母函式

傳送門
其實是個假的多項式快速冪
\(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;
}