WXH的神仙题 FLOJ Round
有n个数排成环,这n个数是1到n的排列,然后你从1出发,每次经过一个数你有 的概率拿走这个数,然后你最后拿走的n个数的排列,假如这个排列在所有排列中字典序从是小到大第k个,你将获得k的权值,问最后的权值期望大小
首先考虑怎么算一个排列的字典序排名
int ans=1;
for(int i=1;i<=n;i++){
int rk=a[i];
for(int j=1;j<i;j++)if(a[j]<a[i])rk--;
ans+=(rk-1)*fac[n-i];//fac是阶乘
}
利用期望的线性性把一个排列的贡献拆成一个数在不同位置的贡献
1+++++
第i个数被第j个删掉的概率
每次只考虑位置1的贡献 计算完之后旋转序列
如果位置1被删除 位置i变成i-1 剩下的数减少
如果位置1没删除 位置i变成i-1 剩下的数不变
(用np和nq分别表示成功、失败的概率)
还有n个数没有删 考虑第i个数被第j个删除的概率
边界是
然后把j压缩一下 变成还有n个数没有删 考虑第i个数的贡献
边界是
2+++++
第i个数被第j个删掉且p在i之前删掉的概率
还有n个数没有删 考虑第i个数被第j个删除且p在i之前删除的概率
边界是
然后发现好像p不好存储
且好像当删除的数是在i和p之间的时候会出事情
然后就可以记录一下i和p的距离
还有n个数没有删 第i个数被第j个删除且i+d位置的数在i之前删除的概率
边界是
然后是可以把j那个维度压缩掉的吧
还有n个数没有删 第i个数在i+d之后删除的贡献
边界是
#include<bits/stdc++.h>
using namespace std;
#define MAXN 310
#define Mod 1000000007
int N,p,q;
int a[MAXN],fac[MAXN],f[MAXN][MAXN],g[MAXN][MAXN][MAXN];
int add(int a,int b){return (a+b)%Mod;}
int sub(int a,int b){return (a-b+Mod)%Mod;}
int mul(int a,int b){return 1ll*a*b%Mod;}
int fast_pow(int a,int b){
int res=1;
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int inv(int a){return fast_pow(a,Mod-2);}
void init(){
fac[0]=1;
for(int i=1;i<=N;++i)fac[i]=mul(fac[i-1],i);
}
int main(){
scanf("%d%d%d",&N,&p,&q);
for(int i=1;i<=N;++i)scanf("%d",&a[i]);
init();
int np=mul(p,inv(q));
int nq=sub(1,np);
int ans=1;
for(int n=1;n<=N;++n){
int tmp=1,cal=fac[n-1];
for(int i=n;i>1;--i){
tmp=mul(tmp,nq);
cal=add(cal,mul(tmp,f[n-1][i-1]));
}
cal=mul(cal,np);
tmp=sub(1,mul(tmp,nq));
f[n][1]=mul(cal,inv(tmp));
for(int i=2;i<=n;++i)
f[n][i]=add(mul(np,f[n-1][i-1]),mul(nq,f[n][i-1]));
}
for(int i=1;i<=N;++i)ans=add(ans,mul(a[i],f[N][i]));
for(int n=1;n<=N;++n){
for(int d=1;d<n;++d){
int cal=f[n-1][d],tmp=1;
for(int i=n;i>1;--i){
tmp=mul(tmp,nq);
if(i+d!=n+1)cal=add(cal,mul(tmp,g[n-1][d-(i+d>n)][i-1]));
}
cal=mul(cal,np);
tmp=sub(1,mul(tmp,nq));
g[n][d][1]=mul(cal,inv(tmp));
for(int i=2;i<=n;++i){
g[n][d][i]=mul(nq,g[n][d][i-1]);
if(i+d!=n+1)g[n][d][i]=add(g[n][d][i],mul(np,g[n-1][d-(i+d>n)][i-1]));
}
}
}
for(int i=1;i<=N;++i)
for(int j=1;j<=N;++j)
if(a[j]<a[i])ans=sub(ans,g[N][(i-j+N)%N][j]);
for(int i=1;i<=N;++i)ans=sub(ans,fac[N-i]);
printf("%d",ans);
return 0;
}