cdqz2017-test10-柚的策略(期望DP & 组合数学)

时间:2021-02-25 08:29:15

cdqz2017-test10-柚的策略(期望DP & 组合数学)

根据期望的可加性,我们可以算出每一位客人的期望等待时间,将他们累加

即 每一位客人所有可能情况的时间之和 / n!

设S= 每一位客人所有可能情况的时间之和

如果有f(i,p)种方案使客人i是恰好第p个进入花亭的,那对S的贡献为(n-p+1)* t[i] * f(i,p)

所以问题转变为计算f(i,p),客人i是恰好第p个进入花亭的方案数

这个恰好很难算

所以转化为在前p个进入花亭的客人中有i,最后f(i,p)减f(i,p-1)就得到了恰好是第p个

若前k+p-1个客人中至少有k-1个客人的用时比第i个客人的用时多,那么客人i可以在前p个进入花亭

所以问题又转化为了计算dp(i,j,l),在i个客人里至少有j个客人的用时比第l个客人用时多,且第i个客人一定在这i个客人里的方案数

换个状态定义会更好算:

用时相同的客人谁先进谁后进对答案没有影响

将客人的用时映射到1——n

dp(i,j,l),在1——n里选i个数至少有j个数比l大 且 不能选l的方案数

可以得到方程:(把f换成dp)

cdqz2017-test10-柚的策略(期望DP & 组合数学)

有了dp(i,j,l),再来算f(i,p)

前面说了若前k+p-1个客人中至少有k-1个客人的用时比第i个客人的用时多,那么客人i可以在前p个进入花亭

假设t[i]映射到了c

所以f(i,p)= dp[k+p-1-1][k-1][c]*(k+p-1)*(n-(k+p-1))!

因为客人i要占据一个位置,这个位置有(k+p-1)种选择,

在客人i之后的客人可以随意组合,所以是全排列

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; #define N 301
#define M 1000001 const int mod=1e9+; int t[N];
int v[M],rk[N]; int C[N][N];
int fac[N]; int dp[N][N][N];
int f[N][N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} int Pow(int a,int b)
{
int res=;
for(;b;a=1LL*a*a%mod,b>>=)
if(b&) res=1LL*a*res%mod;
return res;
} int main()
{
freopen("strategy.in","r",stdin);
freopen("strategy.out","w",stdout);
int n,k;
read(n); read(k);
for(int i=;i<=n;++i) read(t[i]),v[t[i]]++;
for(int i=;i<M;++i) v[i]+=v[i-];
for(int i=;i<=n;++i) rk[i]=v[t[i]]--;
C[][]=;
fac[]=;
for(int i=;i<=n;++i)
{
C[i][]=;
fac[i]=1LL*fac[i-]*i%mod;
for(int j=;j<=i;++j) C[i][j]=(C[i-][j-]+C[i-][j])%mod;
}
for(int i=;i<=n;++i)
{
for(int j=;j<=i;++j)
for(int l=;l<=n;++l)
dp[i][j][l]=1LL*C[n-l][j]*C[l-][i-j]%mod*fac[i]%mod;
//选i个数恰好有j个数比l大的方案数
for(int j=i;j>=;--j)
for(int l=;l<=n;++l)
{
dp[i][j][l]+=dp[i][j+][l];
dp[i][j][l]-=dp[i][j][l]>=mod ? mod : ;
}
//选i个数至少有j个数比l大的方案数
}
int c,m,h;
int ans=;
for(int i=;i<=n;++i)
{
c=rk[i];
for(int j=;j<=n;++j) // 第i个人是前j个进入花亭的
{
m=min(k+j-,n);
h=k--max(,k+j--n);
f[i][j]=1LL*dp[m-][h][c]*m%mod*fac[n-m]%mod;
}
for(int j=n;j;--j)
{
f[i][j]-=f[i][j-];
if(f[i][j]<) f[i][j]+=mod;
ans=(ans+1LL*f[i][j]*(n-j+)%mod*t[i]%mod)%mod;
// printf("%d\n",ans);
}
}
ans=1LL*ans*Pow(fac[n],mod-)%mod;
printf("%d",ans);
}