P5131 荷取融合

Luogu 链接

题意

题目描述

求在 \(n\) 个正整数 \(a_i\) 中选取可以重复的 \(k\) 个数的乘积的期望,结果对 \(19260817\) 取模。


输入格式

第一行两个正整数 \(n\)\(k\)\(1\le n\le10^5,1\le k\le300\)),含义见题目描述
第二行 \(n\) 个正整数 \(a_i\)\(1\le a_i<19260817\)),含义见题目描述


输出格式

题目描述

思路

显然,这一问题可以转化为求方案总数所有方案的贡献和

求方案总数

\(G_{i,j}\) 为前 \(i\) 个数选 \(j\) 个的方案数。

则有:\(G_{i,j}=G_{i-1,j}+G_{i,j-1}\)

即考虑是否选择 \(a_i\)\(G_{i-1,j}\) 为不选择 \(a_i\) 的方案数,\(G_{i,j-1}\) 为选择 \(a_i\) 的方案数。

为了方便转移,令 \(G_{i,0}=1,G_{0,j}=0\)

求所有方案的贡献和

\(F_{i,j}\) 为前 \(i\) 个数选 \(j\) 个的方案的贡献。

则有:\(F_{i,j}=F_{i-1,j}+a_i\times F_{i,j-1}\)

即考虑是否选择 \(a_i\)\(F_{i-1,j}\) 为不选择 \(a_i\) 的贡献,\(a_i\times F_{i,j-1}\) 为选择 \(a_i\) 的贡献。

为了方便转移,令 \(F_{i,0}=1,F_{0,j}=0\)

求期望

期望即 \(\dfrac{F_{n,k}}{G_{n,k}}\),用快速幂求 \(G_{n,k}\) 的逆元即可。

优化空间复杂度

若开二维数组,则空间会炸掉,考虑把第一维压掉。

注意到 \(F_j\)\(G_j\) 在转移时须保证 \(F_{j-1}\)\(G_{j-1}\) 更新过,而本身没被更新,因此第二层循环只需正序枚举即可保证正确性。

程序

AC 记录

#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<iomanip>
#include<string>
#include<stack>
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define vl __int128
#define ld long double
#define INF 0x3f3f3f3f
#define ls rt<<1
#define rs rt<<1|1
#define lb(x) ((x)&(-(x)))
#define pb push_back
#define forUp(i,a,b) for(int i=(a);i<=(b);++i)
#define forDown(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int N=1e5+10,K=300+10,mod=19260817;
//#define use_file
//#define more_test
//#define need_init
#ifdef more_test
int T;
#endif

int n,k,a[N];

int F[K],G[K];

int qp(int x,int y,int mod){
	int ans=1;
	while(y){
		if(y&1)ans=1ll*ans*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return ans;
}

void SOLVE(/*int TestID*/){
	scanf("%d%d",&n,&k);
	forUp(i,1,n)scanf("%d",&a[i]);
	F[0]=G[0]=1;
	forUp(i,1,n){
		forUp(j,1,k){
			F[j]=(F[j]+1ll*a[i]*F[j-1])%mod;
			G[j]=(G[j]+G[j-1])%mod;
		}
	}
	printf("%lld",1ll*F[k]*qp(G[k],mod-2,mod)%mod);
}
/*
Input:

Output:

*/
int main(){
	#ifdef use_file
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	#endif
	#ifdef need_init
	init();
	#endif
	#ifdef more_test
	scanf("%d",&T);
	for(int i=1;i<=T;++i)SOLVE(i);
	#else
	SOLVE();
	#endif
	return 0;
}
posted @ 2025-04-07 19:00  LXcjh4998  阅读(15)  评论(0)    收藏  举报