zoukankan      html  css  js  c++  java
  • [HAOI2011] Problem c

    Description

    (n)个人(n)个座位,需要给每个人确定一个(1-n)的编号,编号可以相同。

    接着从第一个人开始依次入座,每个人会尝试坐到(a_i),如果(a_i)被占据了,就尝试(a_{i+1},a_{i+2}dots a_n)。如果尝试到第(n)个还不行,这个安排方案就不合法。同时有(m)个人的编号已经确定了,只能安排剩下的人的编号。求合法的安排方案。

    Solution

    首先考虑什么是不合法的方案。

    (sum[i])表示最多可以让多少人编号(leq i)

    如果(sum[i]<i)那该方案就不合法

    正确性挺显然的,就是入座的时候只可能编号小的人坐到编号大的座位上,不能从大到小坐。如果(sum[i]<i),那就是再怎么坐前(i)个也坐不满,肯定不合法。

    然后考虑DP解决这个问题。考虑每个位置可以放哪些元素。

    沿用刚才的状态设计思路,设(f[i][j])表示有(j)个人编号(leq i)的方案数,那么(ileq jleq sum[i])

    枚举编号恰好为(i)的有(k)个,那么(cnt[i]leq kleq j-(i-1)),其中(cnt[i])表示钦定编号为(i)的个数,(j-(i-1))是至少要给前(i-1)个位置留(i-1)个人来填满。

    那转移就是(f[i][j]+=f[i-1][j-k] imes C(sum[i]-cnt[i]-j+k,k-cnt[i])),(sum[i]-cnt[i]-j+k)的意义是,给第(i)个最多留出来(sum[i]-cnt[i])个空位,再减去前(i-1)个用过的(j-k)个就是这么多了。

    Code

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<cctype>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    const int N=305;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    
    int sum[N],c[N][N];
    int f[N][N],ZYZ,cnt[N];
    
    int getint(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    signed main(){
        int T=getint();
        while(T--){
            memset(f,0,sizeof f);
            memset(c,0,sizeof c);
            memset(cnt,0,sizeof cnt);
            memset(sum,0,sizeof sum);
            int n=getint(),m=getint();ZYZ=getint();
            for(int i=1;i<=m;i++)
                getint(),cnt[getint()]++;
            sum[0]=n-m;int flag=0;
            for(int i=1;i<=n;i++) {
                sum[i]=sum[i-1]+cnt[i];
                if(sum[i]<i) {
                    flag=1;
                    printf("NO
    ");
                    break;
                }
            } if(flag) continue;
            c[0][0]=1;
            for(int i=1;i<=n;i++){
                c[i][0]=1;
                for(int j=1;j<=n;j++)
                    c[i][j]=(c[i-1][j-1]+c[i-1][j])%ZYZ;
            }
            f[0][0]=1;
            for(int i=1;i<=n;i++){
                for(int j=i;j<=sum[i];j++){
                    for(int k=cnt[i];k<=j-i+1;k++)
                        f[i][j]=(1ll*f[i][j]+1ll*f[i-1][j-k]*c[sum[i]-cnt[i]-j+k][k-cnt[i]]%ZYZ)%ZYZ;
                }
            } printf("YES %d
    ",f[n][n]);
        } return 0;
    }
    
  • 相关阅读:
    Java框架之Mybatis(一)
    Java框架之Hibernate(四)
    Java框架之Hibernate(三)
    递归与分治
    散列
    绪论
    系统的分类(二)
    系统的定义与分类(一)
    Guess My Number 游戏
    2.5 随机数的生成
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9881027.html
Copyright © 2011-2022 走看看