P5131 荷取融合
题意
题目描述
求在 \(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}\) 更新过,而本身没被更新,因此第二层循环只需正序枚举即可保证正确性。
程序
#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;
}

浙公网安备 33010602011771号