zoukankan      html  css  js  c++  java
  • CodeChef LEMOVIE

    题意:给你n个数字(下标不同数值相同的数字应当被认为是不同的数字),有n!种排列方式.每种排列方式的价值定义为:第一次出现时比前面的所有数字都大的数值个数.

    比如1,2,2,3这个排列中,1,2,3这三个数值第一次出现的时候都比前面的所有数字都大,所以这个排列的价值是3.

    1,3,1,2这个排列中,1和3第一次出现的时候比前面的所有数字都大,所以这个排列的价值是2.

    30分n<=10,另外30分所有数值互不相同.

    n<=10只需要n!枚举,所有数值互不相同的时候,我们可以考虑向序列中从大到小一个一个添加数字,那么新添加的数字必须位于当前序列的最前面才会使序列的价值+1,否则序列的价值不变,定义f[i][j]为放置最大的i个数字且当前价值为j的方案数,那么f[i][j]=f[i-1][j-1]+f[i-1][j]*(i-1)

    100分的做法需要我们解决一下数值重复出现的情况.那么还是从大到小考虑每一个数值,只需要考虑新加入的数值是否会对答案贡献1.如果所有新加入的数值前面至少有一个原先存在的较大的数值,那么就不会产生贡献.假如原来有x个较大的数值,现在插入y个大小相同的较小数值,那么总的方案数为C(x+y,y),如果要求这y个数值不能产生贡献,即插入后的序列的第一个数还得是原先x个数中的第一个,那么总的方案数为C(x-1+y,y),产生贡献的方案数用总方案数减一下就可以了.

    比HEOI2013SAO简单多了.

    #include<cstdio>
    #include<cstring>
    typedef long long ll;
    const ll mod=1000000007;
    const int maxn=505;
    ll fac[maxn];
    ll C[maxn][maxn];
    void init(){
        fac[0]=1;
        for(int i=1;i<maxn;++i)fac[i]=fac[i-1]*i%mod;
        C[0][0]=1;
        for(int i=1;i<maxn;++i){
            C[i][0]=1;
            for(int j=1;j<=i;++j){
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
            }
        }
    }
    int cnt[maxn];
    int f[maxn][maxn];
    int main(){
        init();  
        int tests;scanf("%d",&tests);
        while(tests--){
            memset(cnt,0,sizeof(cnt));memset(f,0,sizeof(f));
            int n,k;scanf("%d%d",&n,&k);
            int x;
            for(int i=1;i<=n;++i){
                scanf("%d",&x);cnt[x]++;
            }
            int tot=0,sum=0;
            for(int i=200;i>=1;--i){//1<=Ai<=200
                if(cnt[i]!=0){
                    if(tot==0){
                        ++tot;f[1][1]=fac[cnt[i]];
                    }else{
                        ++tot;
                        ll sol0=C[sum+cnt[i]-1][cnt[i]]*fac[cnt[i]]%mod,sol1=(C[sum+cnt[i]][cnt[i]]*fac[cnt[i]]%mod-sol0+mod)%mod;;
                        for(int j=0;j<=tot;++j){
                            f[tot][j]=(f[tot][j]+f[tot-1][j]*sol0%mod)%mod;
                            if(j>0)f[tot][j]=(f[tot][j]+f[tot-1][j-1]*sol1%mod)%mod;
                        }
                    }
                    sum+=cnt[i];
                }
            }
            ll ans=0;
            for(int i=0;i<=k;++i)ans=(ans+f[tot][i])%mod;
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    阿里云Centos 8.2安装LNMP环境
    TP6中缓存的使用
    TP6中命令行
    TP6中请求和响应
    TP6模型操作
    TP6中数据库操作
    TP6中验证器的使用
    TP6如何使用文件上传
    3. Longest Substring Without Repeating Characters
    1. Two Sum
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6505717.html
Copyright © 2011-2022 走看看