Description
m種物品,第i種物品的權值爲(ui+v),每種物品有無數個,一種取法的代價爲所取物品權值乘積,
問取n個物品的所有不同取法的代價和,
兩個取法不同當且僅當存在一種物品在兩個方案中取得數量不同,
n≤1018,m≤2∗105,mo=109+7
Solution
顯然的,我們要求這個東西的第n項:
i=1∏m(j=0∑(vi+u)jxj)
生成函數寫出來:
ans=[xn]i=1∏m1−(vi+u)x1
先拋出結論(下面的構造過程就是證明):存在以下等式
設pi=(vi+u)
i=1∏m1−pix1=(vx)m−11i=1∑m1−pixai
其中ai爲係數,
還有一個東西:a1∗b1=(a1−b1)b−a1
考慮增量構造,每次乘上一個1−pix1,考慮係數ai的變化
爲了方便,我們設加入第j個元素後第i位的係數爲aj,i
當前我們加入第j位:
(vx)−j+1(i=1∑j−11−pixaj−1,i)(1−pjx1)
(vx)−j+1i=1∑j−1(aj−1,i∗1−pix1∗1−pjx1)
用上面那個東西拆開:
(vx)−j+1i=1∑j−1aj−1,i(1−pix1−1−pjx1)((pi−pj)x1)
把最後面的p拆開:
(vx)−j+1i=1∑j−1aj−1,i(1−pix1−1−pjx1)((i−j)vx1)
再把最後面那個的vx1提到前面,並把剩下的乘進去:
(vx)−ji=1∑j−1−(j−i)aj−1,i1−pix1+(j−i)aj−1,i1−pjx1
我們發現一開始的項又出來了,也就是aj−1與aj之間存在以下關係:
aj,i=−(j−i)1∗aj−1,i,當i<j
aj,i=k=1∑j−1(j−k)1∗aj−1,k,當i=j
也就是對於j>k,有:
aj,i=ak,i∗l=k∏j−1−(j−l)1=ak,i∗(j−k)!(−1)j−k
我們設fi=ai,i,即i這一項第一次出現時的值,有:
fi=j=1∑i−1(i−j)1∗ai−1,j=j=1∑i−1fj∗(i−j)!(−1)i−j−1
不難發現,f就是個卷積式,也就是:
f=f∗(i=1∑i!(−1)i−1)
寫成生產函數的形式:(一次項記得加上)
f=f∗(1−e−x)+x
解得:
f=xex
也就是:
fi=(i−1)!1
解出了f剩下的就好辦了,直接算即可,
(vx)m−11i=1∑m(i−1)!(m−i)!(−1)m−i∗1−pix1
複雜度:O(nlog(109))
Code
#include <cstdio>
#include <algorithm>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=200500,mo=998244353;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,ans;
LL n,K,nw;
LL f[N];
LL jc[N],jcn[N];
LL ksm(LL q,LL w)
{
LL ans=1;
for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
return ans;
}
int main()
{
freopen("ioer.in","r",stdin);
freopen("ioer.out","w",stdout);
int q,w,_;
n=2e5;
jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mo;
jcn[n]=ksm(jc[n],mo-2);fod(i,n-1,0)jcn[i]=jcn[i+1]*(i+1LL)%mo;
read(_);
while(_--)
{
scanf("%lld%d%lld%lld",&n,&m,&K,&nw);
ans=0;
fo(i,1,m)
{
nw=(nw+K)%mo;
f[i]=jcn[i-1]*jcn[m-i]%mo*((m-i)&1?-1:1);
ans=(ans+f[i]*ksm(nw,n+m-1))%mo;
}
ans=ans*ksm(ksm(K,m-1),mo-2)%mo;
printf("%lld\n",(ans+mo)%mo);
}
return 0;
}