zoukankan      html  css  js  c++  java
  • 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)

    有了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+7;
    
    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=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } 
    }
    
    int Pow(int a,int b)
    {
        int res=1;
        for(;b;a=1LL*a*a%mod,b>>=1)
            if(b&1) 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=1;i<=n;++i) read(t[i]),v[t[i]]++;
        for(int i=1;i<M;++i) v[i]+=v[i-1];
        for(int i=1;i<=n;++i) rk[i]=v[t[i]]--;
        C[0][0]=1;
        fac[0]=1;
        for(int i=1;i<=n;++i)
        {
            C[i][0]=1;
            fac[i]=1LL*fac[i-1]*i%mod;
            for(int j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
        for(int i=0;i<=n;++i)
        {
            for(int j=0;j<=i;++j)
                for(int l=1;l<=n;++l)
                    dp[i][j][l]=1LL*C[n-l][j]*C[l-1][i-j]%mod*fac[i]%mod; 
            //选i个数恰好有j个数比l大的方案数
            for(int j=i;j>=0;--j) 
                for(int l=1;l<=n;++l)
                {
                    dp[i][j][l]+=dp[i][j+1][l]; 
                    dp[i][j][l]-=dp[i][j][l]>=mod ? mod : 0;
                }
            //选i个数至少有j个数比l大的方案数
        }
        int c,m,h; 
        int ans=0;
        for(int i=1;i<=n;++i)
        {
            c=rk[i];
            for(int j=1;j<=n;++j) // 第i个人是前j个进入花亭的 
            {
                m=min(k+j-1,n);
                h=k-1-max(0,k+j-1-n);
                f[i][j]=1LL*dp[m-1][h][c]*m%mod*fac[n-m]%mod; 
            }
            for(int j=n;j;--j)
            {
                f[i][j]-=f[i][j-1];
                if(f[i][j]<0) f[i][j]+=mod;
                ans=(ans+1LL*f[i][j]*(n-j+1)%mod*t[i]%mod)%mod;
            //    printf("%d
    ",ans);
            }
        }
        ans=1LL*ans*Pow(fac[n],mod-2)%mod; 
        printf("%d",ans);
    }
  • 相关阅读:
    Android的startActivityForResult()与onActivityResult()与setResult()参数分析,activity带参数的返回
    git stash 保存当前工作状态
    vim diff 的使用
    git pull 命令
    java 开发环境安装
    vim 处理换行符
    git 操作分支
    git 操作远程仓库地址
    vim 宏的使用
    Chrome 调试技巧
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8719157.html
Copyright © 2011-2022 走看看