【JZOJ 6080】【GDOI2019模拟2019.3.23】IOer

Description

m种物品,第i种物品的权值为 ( u i + v ) (ui+v) (ui+v),每种物品有无数个,一种取法的代价为所取物品权值乘积,
问取n个物品的所有不同取法的代价和,
两个取法不同当且仅当存在一种物品在两个方案中取得数量不同,

n ≤ 1 0 18 , m ≤ 2 ∗ 1 0 5 , m o = 1 0 9 + 7 n\leq10^{18},m\leq 2*10^5,mo=10^9+7 n1018,m2105,mo=109+7

Solution

显然的,我们要求这个东西的第n项:
∏ i = 1 m ( ∑ j = 0 ( v i + u ) j x j ) \prod_{i=1}^m(\sum_{j=0}(vi+u)^jx^j) i=1m(j=0(vi+u)jxj)
生成函数写出来:
a n s = [ x n ] ∏ i = 1 m 1 1 − ( v i + u ) x ans=[x_n]\prod_{i=1}^m\frac{1}{1-(vi+u)x} ans=[xn]i=1m1(vi+u)x1
先抛出结论(下面的构造过程就是证明):存在以下等式
p i = ( v i + u ) p_i=(vi+u) pi=(vi+u)
∏ i = 1 m 1 1 − p i x = 1 ( v x ) m − 1 ∑ i = 1 m a i 1 − p i x \prod_{i=1}^m\frac{1}{1-p_ix}=\frac{1}{(vx)^{m-1}}\sum_{i=1}^m\frac{a_i}{1-p_ix} i=1m1pix1=(vx)m11i=1m1pixai
其中 a i a_i ai为系数,

还有一个东西: 1 a ∗ 1 b = ( 1 a − 1 b ) 1 b − a \frac{1}{a}*\frac{1}{b}=(\frac{1}{a}-\frac{1}{b})\frac{1}{b-a} a1b1=(a1b1)ba1

考虑增量构造,每次乘上一个 1 1 − p i x \frac{1}{1-p_ix} 1pix1,考虑系数 a i a_i ai的变化
为了方便,我们设加入第j个元素后第i位的系数为 a j , i a_{j,i} aj,i
当前我们加入第j位:
( v x ) − j + 1 ( ∑ i = 1 j − 1 a j − 1 , i 1 − p i x ) ( 1 1 − p j x ) (vx)^{-j+1}(\sum_{i=1}^{j-1}\frac{a_{j-1,i}}{1-p_ix})(\frac{1}{1-p_jx}) (vx)j+1(i=1j11pixaj1,i)(1pjx1)

( v x ) − j + 1 ∑ i = 1 j − 1 ( a j − 1 , i ∗ 1 1 − p i x ∗ 1 1 − p j x ) (vx)^{-j+1}\sum_{i=1}^{j-1}(a_{j-1,i}*\frac{1}{1-p_ix}*\frac{1}{1-p_jx}) (vx)j+1i=1j1(aj1,i1pix11pjx1)
用上面那个东西拆开:

( v x ) − j + 1 ∑ i = 1 j − 1 a j − 1 , i ( 1 1 − p i x − 1 1 − p j x ) ( 1 ( p i − p j ) x ) (vx)^{-j+1}\sum_{i=1}^{j-1}a_{j-1,i}(\frac{1}{1-p_ix}-\frac{1}{1-p_jx})(\frac{1}{(p_i-p_j)x}) (vx)j+1i=1j1aj1,i(1pix11pjx1)((pipj)x1)
把最后面的p拆开:
( v x ) − j + 1 ∑ i = 1 j − 1 a j − 1 , i ( 1 1 − p i x − 1 1 − p j x ) ( 1 ( i − j ) v x ) (vx)^{-j+1}\sum_{i=1}^{j-1}a_{j-1,i}(\frac{1}{1-p_ix}-\frac{1}{1-p_jx})(\frac{1}{(i-j)vx}) (vx)j+1i=1j1aj1,i(1pix11pjx1)((ij)vx1)
再把最后面那个的 1 v x \frac{1}{vx} vx1提到前面,并把剩下的乘进去:

( v x ) − j ∑ i = 1 j − 1 a j − 1 , i − ( j − i ) 1 1 − p i x + a j − 1 , i ( j − i ) 1 1 − p j x (vx)^{-j}\sum_{i=1}^{j-1}\frac{a_{j-1,i}}{-(j-i)}\frac{1}{1-p_ix}+\frac{a_{j-1,i}}{(j-i)}\frac{1}{1-p_jx} (vx)ji=1j1(ji)aj1,i1pix1+(ji)aj1,i1pjx1
我们发现一开始的项又出来了,也就是 a j − 1 a_{j-1} aj1 a j a_j aj之间存在以下关系:
a j , i = − 1 ( j − i ) ∗ a j − 1 , i , 当 i < j a_{j,i}=-\frac{1}{(j-i)}*a_{j-1,i},当i<j aj,i=(ji)1aj1,ii<j
a j , i = ∑ k = 1 j − 1 1 ( j − k ) ∗ a j − 1 , k , 当 i = j a_{j,i}=\sum_{k=1}^{j-1}\frac{1}{(j-k)}*a_{j-1,k},当i=j aj,i=k=1j1(jk)1aj1,ki=j

我们设 f i = a i , i f_i=a_{i,i} fi=ai,i,即i这一项第一次出现时的值,有:
f i = ∑ j = 1 i − 1 1 ( i − j ) ∗ a i − 1 , j = ∑ j = 1 i − 1 f j ∗ ( − 1 ) i − j − 1 ( i − j ) ! f_i=\sum_{j=1}^{i-1}\frac{1}{(i-j)}*a_{i-1,j}=\sum_{j=1}^{i-1}f_j*\frac{(-1)^{i-j-1}}{(i-j)!} fi=j=1i1(ij)1ai1,j=j=1i1fj(ij)!(1)ij1

不难发现,f就是个卷积式,也就是:
f = f ∗ ( ∑ i = 1 ( − 1 ) i − 1 i ! x i ) + x f=f*(\sum_{i=1}\frac{(-1)^{i-1}}{i!}x^i)+x f=f(i=1i!(1)i1xi)+x
写成生产函数的形式:(一次项记得加上)
f = f ∗ ( 1 − e − x ) + x f=f*(1-e^{-x})+x f=f(1ex)+x
解得:
f = x e x f=xe^x f=xex
也就是:
f i = 1 ( i − 1 ) ! f_i=\frac{1}{(i-1)!} fi=(i1)!1
解出了 f f f剩下的就好办了,直接算即可,

1 ( v x ) m − 1 ∑ i = 1 m ( − 1 ) m − i ( i − 1 ) ! ( m − i ) ! ∗ 1 1 − p i x \frac{1}{(vx)^{m-1}}\sum_{i=1}^m\frac{(-1)^{m-i}}{(i-1)!(m-i)!}*\frac{1}{1-p_ix} (vx)m11i=1m(i1)!(mi)!(1)mi1pix1

复杂度: O ( n log ⁡ ( 1 0 9 ) ) O(n\log(10^9)) O(nlog(109))

Code

#include 
#include 
#include 
#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;
}

你可能感兴趣的:(妙啊,生成函数)