WXH的神仙题 FLOJ Round【概率DP】*

版权声明:欢迎转载,请注明出处,谢谢 https://blog.csdn.net/Dream_maker_yk/article/details/82026395

WXH的神仙题 FLOJ Round


有n个数排成环,这n个数是1到n的排列,然后你从1出发,每次经过一个数你有 p q 的概率拿走这个数,然后你最后拿走的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是阶乘
}

利用期望的线性性把一个排列的贡献拆成一个数在不同位置的贡献
a n s = s u m ( f a c [ n i ] ) + s u m ( a [ i ] f a c [ n i ] ) s u m ( ( a [ j ] < a [ i ] ) f a c [ n i ] )
f i n a l a n s = s u m ( f a c [ n i ] )
1+++++
f i n a l a n s + = P [ i ] [ j ] a [ i ] f a c [ n j ]
P [ i ] [ j ] : 第i个数被第j个删掉的概率
每次只考虑位置1的贡献 计算完之后旋转序列
如果位置1被删除 位置i变成i-1 剩下的数减少
如果位置1没删除 位置i变成i-1 剩下的数不变
(用np和nq分别表示成功、失败的概率)
d p [ n ] [ i ] [ j ] 还有n个数没有删 考虑第i个数被第j个删除的概率
d p [ n ] [ i ] [ j ] = n p d p [ n 1 ] [ i 1 ] [ j ] + n q d p [ n ] [ i 1 ] [ j ]
边界是 d p [ n ] [ 1 ] [ 1 ] = n p + n q d p [ n ] [ n ] [ 1 ]
然后把j压缩一下 变成还有n个数没有删 考虑第i个数的贡献
d p [ n ] [ i ] = n p d p [ n 1 ] [ i 1 ] + n q d p [ n ] [ i 1 ]
边界是 d p [ n ] [ 1 ] = n p f a c [ n 1 ] + n q d p [ n ] [ n ]

2+++++
f i n a l a n s = P [ i ] [ j ] [ p ] f a c [ n j ]
P [ i ] [ j ] [ p ] 第i个数被第j个删掉且p在i之前删掉的概率
d p [ n ] [ p ] [ i ] [ j ] 还有n个数没有删 考虑第i个数被第j个删除且p在i之前删除的概率
d p [ n ] [ p ] [ i ] [ j ] = n p d p [ n 1 ] [ p 1 ] [ i 1 ] [ j ] + n q d p [ n ] [ p 1 ] [ i 1 ] [ j ]
边界是 d p [ n ] [ p ] [ 1 ] [ 1 ] = n p + n q d p [ n ] [ p 1 ] [ i 1 ] [ 1 ]
然后发现好像p不好存储
且好像当删除的数是在i和p之间的时候会出事情
然后就可以记录一下i和p的距离
d p [ n ] [ d ] [ i ] [ j ] 还有n个数没有删 第i个数被第j个删除且i+d位置的数在i之前删除的概率
d p [ n ] [ d ] [ i ] [ j ] = n p d p [ n 1 ] [ d ( i + d > N ) ] [ i 1 ] [ j ] + n q d p [ n 1 ] [ d ] [ i 1 ] [ j ]
边界是 d p [ n ] [ d ] [ 1 ] [ 1 ] = n p + n q d p [ n ] [ d ] [ n ] [ 1 ]
然后是可以把j那个维度压缩掉的吧
d p [ n ] [ d ] [ i ] 还有n个数没有删 第i个数在i+d之后删除的贡献
d p [ n ] [ d ] [ i ] = n p d p [ n 1 ] [ d ( i + d > N ) ] [ i 1 ] + n q d p [ n ] [ d ] [ i 1 ]
边界是 d p [ n ] [ d ] [ 1 ] = n p d p [ n 1 ] [ d ] ( 1 ) + n q d p [ n ] [ d ] [ n ]


#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;
}

猜你喜欢

转载自blog.csdn.net/Dream_maker_yk/article/details/82026395