Luogu4389.付公主的背包

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/81611230

题意:

付公主有一个可爱的背包qwq
这个背包最多可以装 10 5 大小的东西
付公主有 n 种商品,她要准备出摊了.
每种商品体积为 V i ,都有 10 5 件.
给定m,对于 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;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/81611230