zoukankan      html  css  js  c++  java
  • CodeChef Little Elephant and Movies [DP 排列]

    https://www.codechef.com/FEB14/problems/LEMOVIE

    题意:

    对于一个序列,定义其“激动值”为序列中严格大于前面所有数的元素的个数。
    给定n个数p1;,p2... pn,求这n个数的所有排列中,激动值不超过k的个数。$1 k le n le 200,1 le pi le 200$


    这种题有一个很神的想法:

    把排列按某种顺序往里插入,使得后不会影响前

    对于本题,先离散化去重后,从大到小插入,后插入的元素不会影响已经插入的元素严格大于前面所有数

    $f[i][j]$表示插入了前$i$大的数,激动值为$j$的方案数

    激动值改变只有可能是当前要插入的数中有一个放在了最前面

    转移时分类讨论有没有数插在最前面,需要用到隔板法,

    设已经插入$x$个数,第$i$大的有$y$个数

    $f(i,j)=f(i-1,j)*inom{x+y-1}{x-1}*{y!} + f(i-1,j-1)*inom{x+y-1}{x}*{y!}$ 

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=205,INF=1e9+5,P=1e9+7;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,k,a[N];
    int m,d[N],s[N];
    inline bool cmp(int a,int b){return a>b;}
    ll c[N][N],fac[N];
    inline void mod(ll &x){if(x>=P) x-=P;}
    void ini(){
        c[0][0]=1;fac[0]=1;
        for(int i=1;i<=200;i++){
            c[i][0]=1;
            for(int j=1;j<=i;j++) mod(c[i][j]+=c[i-1][j]+c[i-1][j-1]);
            fac[i]=fac[i-1]*i%P;
        }
    }
    ll f[N][N];
    void dp(){
        f[0][0]=1;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=k;j++){
                int x=s[i-1],y=d[i];
                f[i][j]=f[i-1][j]*c[x+y-1][x-1]%P*fac[y]%P;
                mod(f[i][j]+=f[i-1][j-1]*c[x+y-1][x]%P*fac[y]%P);
                //printf("f %d %d %lld
    ",i,j,f[i][j]);
            }
        ll ans=0;
        for(int i=1;i<=k;i++) mod(ans+=f[m][i]);
        printf("%lld
    ",ans);
    }
    int main(){
        freopen("in","r",stdin);
        ini();
        int T=read();
        while(T--){
            memset(d,0,sizeof(d));
            n=read();k=read();
            for(int i=1;i<=n;i++) a[i]=read();
            sort(a+1,a+1+n,cmp);
            m=0;
            d[++m]=1;
            for(int i=2;i<=n;i++){
                if(a[i]==a[i-1]) d[m]++;
                else d[++m]=1;
            }
            for(int i=1;i<=m;i++) s[i]=s[i-1]+d[i];
            //for(int i=1;i<=m;i++) printf("%d ",d[i]);puts("");
            //for(int i=1;i<=m;i++) printf("%d ",s[i]);puts("");
            dp();
        }
    }
  • 相关阅读:
    算法面试准备(一)之----交叉熵与logistic回归推导
    Julia初学备忘
    二维数组中的查找,替换空格
    快慢指针倒数第K个节点,每K个一组反转链表
    贝叶斯网络之----(d-分离步骤)
    一笑
    尾曲
    ggplot在python中的使用(plotnine)
    SVC之SMO算法理解
    特征选取之IV(信息值)及python实现
  • 原文地址:https://www.cnblogs.com/candy99/p/6501669.html
Copyright © 2011-2022 走看看