1. 程式人生 > >Luogu4389.付公主的揹包

Luogu4389.付公主的揹包

題意:

付公主有一個可愛的揹包qwq
這個揹包最多可以裝 10 5 大小的東西
付公主有 n 種商品,她要準備出攤了.
每種商品體積為

V i ,都有 10 5 件.
給定m,對於
[1,m]" role="presentation" style="position: relative;"> s [ 1 , m ] ,請你回答用這些商品恰好裝 s 體積的方案數對 998244353 取模.

資料範圍:

對於30%的資料, n <= 3000 , m <= 3000
對於60%的資料,純隨機生成
對於100%的資料, n <= 100000 , m <= 100000
對於100%的資料, V i <= m

Analysis

首先每種物品都有 10 5 個,可以直接看成有無數個物品。考慮生成函式優化:對於任意一個 V ,設 f ( x ) = i = 0 x V i = 1 1 x V 。我們要求的就是所有這樣的函式的積。但是乘法不好做,我們考慮將 f ( x ) l n g ( x ) ,最後 e x p 得到答案。

g ( x ) = f ( x ) f ( x ) = ( 1 x V ) i = 1 V i x V i 1 = i = 1 V x V i 1
g ( x ) = i = 1 V V i x V i
此時我們只需要將所有 g ( x ) 累加起來,複雜度同篩法 O ( m l o g m ) ,最後多項式 e x p 就好。

Code

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 6e5 + 5;
const int mo = 998244353;
const int g = 3;
const int invg = (mo + 1) / 3;
typedef long long ll;
int A[N],B[N],c[N],d[N],e[N],f[N],w[N][2];
int rev[N],cnt[N],v[N],ans[N],inv[N];
int n,m,l,len;
inline int pow(int x,int p)
{
    int ret = 1;
    for (; p ; p >>= 1,x = (ll)x * x % mo)
        if (p & 1) ret = (ll)ret * x % mo;
    return ret;
}
inline void dft(int *f,int n,int opt)
{
    for (len = 1,l = 0 ; len <= n ; len <<= 1,++l);
    for (int i = 0 ; i < len ; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    for (int i = 0 ; i < len ; ++i) if (i < rev[i]) swap(f[i],f[rev[i]]);
    for (int i = 1 ; i < len ; i <<= 1)
    {
        int wn = (~opt) ? w[i][0] : w[i][1];
        for (int j = 0 ; j < len ; j += (i << 1))
        {
            int w = 1;
            for (int k = 0 ; k < i ; ++k,w = (ll)w * wn % mo)
            {
                int x = (ll)f[j + k + i] * w % mo,y = f[j + k];
                f[j + k] = (x + y) % mo,f[j + k + i] = (y - x + mo) % mo;
            }
        }
    }
    if (opt == -1)
    {
        int x = pow(len,mo - 2);
        for (int i = 0 ; i < len ; ++i) f[i] = (ll)f[i] * x % mo;
    }
}
inline void getinv(int *a,int *b,int n)
{
    if (n == 1) { b[0] = pow(a[0],mo - 2); return; }
    getinv(a,b,n >> 1);
    for (int i = 0 ; i < n ; ++i) A[i] = a[i],B[i] = b[i];
    dft(A,n << 1,1); dft(B,n << 1,1);
    for (int i = 0 ; i < len ; ++i) A[i] = (ll)A[i] * B[i] % mo * B[i] % mo;
    dft(A,n << 1,-1);
    for (int i = 0 ; i < n ; ++i) b[i] = ((b[i] << 1) % mo - A[i] + mo) % mo;
    for (int i = 0 ; i < len ; ++i) A[i] = B[i] = 0;
}
inline void getln(int *a,int *b,int n)
{
    getinv(a,c,n);
    for (int i = 0 ; i < n - 1 ; ++i) d[i] = (ll)(i + 1) * a[i + 1] % mo;
    dft(c,n << 1,1); dft(d,n << 1,1);
    for (int i = 0 ; i < len ; ++i) c[i] = (ll)c[i] * d[i] % mo;
    dft(c,n << 1,-1);
    for (int i = 1 ; i < n ; ++i) b[i] = (ll)inv[i] * c[i - 1] % mo;
    for (int i = 0 ; i < len ; ++i) c[i] = d[i] = 0;
}
inline void getexp(int *a,int *b,int n)
{
    if (n == 1) { b[0] = 1; return; }
    getexp(a,b,n >> 1);
    for (int i = 0 ; i < n ; ++i) e[i] = b[i];
    getln(b,f,n);
    for (int i = 0 ; i < n ; ++i) f[i] = (mo - f[i] + a[i]) % mo; f[0] = (f[0] + 1) % mo;
    dft(e,n << 1,1); dft(f,n << 1,1);
    for (int i = 0 ; i < len ; ++i) e[i] = (ll)e[i] * f[i] % mo;
    dft(e,n << 1,-1);
    for (int i = 0 ; i < n ; ++i) b[i] = e[i];
    for (int i = 0 ; i < len ; ++i) e[i] = f[i] = 0;
}
int main()
{
    scanf("%d%d",&n,&m); inv[1] = 1;
    for (int i = 1 ; i <= n ; ++i)
    { int x; scanf("%d",&x); ++cnt[x]; }
    int zs = 1; for (; zs <= m ; zs <<= 1);
    for (int i = 1 ; i <= (zs << 1) ; i <<= 1) w[i][0] = pow(g,(mo - 1) / (i << 1)),w[i][1] = pow(invg,(mo - 1) / (i << 1));
    for (int i = 2 ; i < zs ; ++i) inv[i] = (ll)(mo - mo / i) * inv[mo % i] % mo;
    for (int i = 1 ; i <= m ; ++i)
    if (cnt[i])
    {
        int del = (ll)i * cnt[i] % mo;
        for (int j = 1 ; i * j <= m ; ++j) v[j * i] = (v[j * i] + del) % mo;
    }
    for (int i = 1 ; i <= m ; ++i) v[i] = (ll)inv[i] * v[i] % mo;
    getexp(v,ans,zs);
    for (int i = 1 ; i <= m ; ++i) printf("%d\n",ans[i]);
    return 0;
}