题解 P5131 荷取融合
分析
首先看数据范围就知道这应该是一个 \(O(nk)\) 的题。考虑 dp。
用 \(f[i][j]\) 表示抓取了 \(i\) 个,最后一个是 \(j\) 的答案之和,\(g[i][j]\) 表示有多少种不同的抓取方案,最后答案就是所有满足要求的 \(f\) 之和除以对应的 \(g\)。
转移时,因为你可以从上一个抓取往右边跑,所以你只会从比 \(j\) 小的地方转移到 \(f[i][j]\) 和 \(g[i][j]\)。所以在循环的同时用两个数分别记录 \(f\) 和 \(g\) 的前缀和即可。
代码
#include
using namespace std;
#define int long long
const int mod=19260817;
inline int qpow(int ds,int zs){
int x=1;
while(zs){
if(zs&1)x=1ll*x*ds%mod;
ds=1ll*ds*ds%mod;zs>>=1;
}
return x;
}
inline void read(int &res){
res=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
res*=f;
}
int n,k;
int ti;
int a[100005],f[2][100005],g[2][100005],b[100005],bb[100005];
//只有128MB,所以要滚动数组
signed main()
{
f[0][1]=1;
g[0][1]=1;
read(n);read(k);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=1;i<=k;i++){
ti^=1;
memset(f[ti],0,sizeof(f[ti]));
memset(g[ti],0,sizeof(g[ti]));
for(int j=1;j<=n;j++){
b[j]=(b[j-1]+f[ti^1][j])%mod;//其实一个数就行了,不需要开数组
bb[j]=(bb[j-1]+g[ti^1][j])%mod;
f[ti][j]=b[j]*a[j]%mod;
g[ti][j]=bb[j];
}
}
int sum=0,cnt=0;
for(int i=1;i<=n;i++){
sum=(sum+f[ti][i])%mod;
cnt=(cnt+g[ti][i])%mod;
}
cout<<(sum*qpow(cnt,mod-2)%mod);
return 0;
}