Thief in a Shop

题意:

问n个物品选出K个可以拼成的体积有哪些。

解法:

多项式裸题,注意到本题中 $A(x)^K$ 的系数会非常大,采用NTT优于FFT。

NTT 采用两个 $2^t+1$ 质数,求原根 $g_n$ 后用 $g_n^1 $~$ g_n^{P-1}$ 的循环代替复数向量的旋转。

注意逆的 $w_n$ 是 $g_n ^ {  - frac{P-1}{len}  }$,并且要用两个质数保证正确即可,$O(nlogn)$。

#include <bits/stdc++.h>

#define PI acos(-1)
#define P1 998244353LL
#define P2 469762049LL
#define LL long long
#define gn 3

const int N = 500010;

using namespace std;

int R[N<<2];

LL qpow(LL x,int n,LL P)
{
    LL ans = 1;
    for(;n;n>>=1,x = x*x % P) if(n&1) ans = ans*x % P;
    return ans;
}

void DFT(LL a[],int n,int tp_k,LL P)
{
    for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]);
    for(int d=1;d<n;d<<=1)
    {
        LL wn = qpow(gn, (P-1)/(d<<1),P);
        if(tp_k == -1) wn = qpow(wn, P-2,P);
        for(int i=0;i<n;i += (d<<1))
        {
            LL wt = 1;
            for(int k=0;k<d;k++, wt = wt*wn % P)
            {
                LL A0 = a[i+k], A1 = wt * a[i+k+d] % P;
                a[i+k] = A0+A1;
                a[i+k+d] = A0+P-A1;
                if(a[i+k] >= P) a[i+k] -= P;
                if(a[i+k+d] >= P) a[i+k+d] -= P;
            }
        }
    }
    LL inv = qpow(n, P-2,P);
    if(tp_k==-1)
        for(int i=0;i<n;i++) a[i] = a[i] * inv % P;
}

LL A[N<<2],B[N<<2];

int main()
{
    //freopen("test.txt","w",stdout);
    int n,K;
    cin>>n>>K;
    int L = 0,tot;
    while((1<<L)<1000*K) L++;
    tot = (1<<L);
    for(int i=1;i<tot;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    for(int i=1,x;i<=n;i++) scanf("%d",&x), A[x] = 1, B[x] = 1;
    DFT(A,tot,1,P1);
    for(int i=0;i<tot;i++) A[i] = qpow(A[i], K, P1);
    DFT(A,tot,-1,P1);
    DFT(B,tot,1,P2);
    for(int i=0;i<tot;i++) B[i] = qpow(B[i], K, P2);
    DFT(B,tot,-1,P2);
    for(int i=0;i<tot;i++) if(A[i] || B[i]) printf("%d ",i);
    printf("
");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lawyer/p/7190865.html