1. 程式人生 > >牛客網Wannafly挑戰賽24 D-無限手套 生成函式

牛客網Wannafly挑戰賽24 D-無限手套 生成函式

題意

有n種物品,每種物品有兩個引數ai,bia_i,b_i。現在可以從每種物品中選出若干個,設第i種物品選了xix_i個,則貢獻i=1n(aix2+bix+1)\prod_{i=1}^n(a_ix^2+b_ix+1)
有q次詢問,每次詢問給出一個m,求所有選的物品總數為m的選擇方案的貢獻和,答案模998244353。
n,q1000,m10000n,q\le1000,m\le10000

分析

顯然一個物品i的生成函式為j0xj(aij2+bij+1)\sum_{j\ge0}x^j(a_ij^2+b_ij+1)

ij+1)
然後這個生成函式可以被我們畫成A(1x)3+B(1x)2+C(1x)\frac{A}{(1-x)^3}+\frac{B}{(1-x)^2}+\frac{C}{(1-x)}
全部乘起來後最終的生成函式是fi(1x)i\sum\frac{f_i}{(1-x)^i}的形式,那麼列舉i然後再乘個組合數就做完了。
一開始推生成函式係數的時候,把i>0xi\sum_{i>0}x^i當成了1(1x)\frac{1}{(1-x)},錯了好久才發現這個問題。

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=10005;
const int MOD=998244353;

int n,ny[N*3],jc[N*3],f[N];

int Calc(int n,int m)
{
	return (LL)jc[n]*ny[m]%MOD*ny[
n-m]%MOD; } int main() { jc[0]=jc[1]=ny[0]=ny[1]=1; for (int i=2;i<=30000;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD; for (int i=2;i<=30000;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD; scanf("%d",&n); f[0]=1; int tot=0; for (int i=1;i<=n;i++) { int a,b;scanf("%d%d",&a,&b); int A=a*2%MOD,B=(b+MOD-(LL)a*3%MOD)%MOD,C=(a+MOD-b+1)%MOD; tot+=3; for (int j=tot;j>=3;j--) { f[j]=0; (f[j]+=(LL)f[j-3]*A%MOD)%=MOD; (f[j]+=(LL)f[j-2]*B%MOD)%=MOD; (f[j]+=(LL)f[j-1]*C%MOD)%=MOD; } f[2]=((LL)f[1]*C%MOD+(LL)f[0]*B%MOD)%MOD; f[1]=(LL)f[0]*C%MOD; f[0]=0; } int q;scanf("%d",&q); while (q--) { int m;scanf("%d",&m); int ans=0; for (int i=1;i<=tot;i++) (ans+=(LL)Calc(m+i-1,i-1)*f[i]%MOD)%=MOD; printf("%d\n",ans); } return 0; }