Codeforces 891E. Lust 生成函数

Solution

每次得到的值可以看做操作后整个序列的乘积减去操作前整个序列的乘积,这样就把问题转化为求最后数列的乘积减去开始数列的乘积。
把式子列出来,设 b i b_i bi a i a_i ai被减去的值,得到 E = 1 n k × k ! Π b i ! × Π ( a i − b i ) E={1\over n^k}\times {k!\over \Pi b_i!}\times {\Pi (a_i-b_i)} E=nk1×Πbi!k!×Π(aibi)
考虑每个数的贡献,因为最后总共是 k k k轮,考虑用生成函数统计贡献,每个函数第 i i i项表示这个数被减了 i i i次的贡献,最后把 n n n个乘起来,第 k k k项就是我们答案。即 F i ( x ) = ∑ a i − j j x j Fi(x)=\sum {a_i-j\over j}x^j Fi(x)=jaijxj
用泰勒展开化简一下,得 F i ( x ) = ( a i − x ) e x Fi(x)=(a_i-x)e^x Fi(x)=(aix)ex
n n n个相乘得到 e n x Π ( a i − x ) e^{nx}\Pi(a_i-x) enxΠ(aix)
e n x e^{nx} enx展开 ∑ ( n x ) i i ! Π ( a i − x ) \sum {(nx)^i\over i!}\Pi(a_i-x) i!(nx)iΠ(aix)
至此已经可以暴力算出第 k k k项系数了,复杂度 O ( n 2 ) O(n^2) O(n2)

Code

#include
using namespace std;
#define LL long long
#define pa pair
const int Maxn=5010;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
void upd(int&x,int y){x+=y;if(x>=mod)x-=mod;}
int Pow(int x,int y)
{
	if(!y)return 1;
	int t=Pow(x,y>>1),re=(LL)t*t%mod;
	if(y&1)re=(LL)re*x%mod;
	return re;
}
int n,k,a[Maxn],f[Maxn],ans=0,s=1;//f[x]x个ai的乘积之和 
int main()
{
	n=read(),k=read();f[0]=1;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();s=(LL)s*a[i]%mod;
		for(int j=i;j;j--)upd(f[j],(LL)a[i]*f[j-1]%mod);
	}
	for(int i=0;i<=n;i++)if((n-i)&1)f[i]=(mod-f[i])%mod;
	int inv=Pow(n,mod-2);
	for(int i=0;i<=min(n,k);i++)
	{
		int t=1;
		for(int j=k;j>k-i;j--)t=(LL)t*j%mod;
		upd(ans,(LL)f[n-i]*t%mod*Pow(inv,i)%mod);
	}
	printf("%d",(s-ans+mod)%mod);
}

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