zoukankan      html  css  js  c++  java
  • Codeforces340 E. Iahub and Permutations

    Codeforces题号:#340E

    出处: Codeforces

    主要算法:思维+DP

    难度:4.8

    题意:

    有一个长度为$n$的排列(即各元素互不相同),其中有一些为-1。现要求将数填到这些-1上,使得原排列是一个错位排列。问有几种方法?

    思路分析:

      又是一道超级难的DP……

      这不就是一个错排的模板题吗?不是只要看有几个-1就做多少的错排吗?确实,样例很不良心,那就给你一组反例吧……

      5

      -1 -1 2 3 -1

      我们注意到了,并不是剩下的元素全是错排。因为原来我们认为2不能处在2的位置,但是4作为第二个元素是可以处在2的位置的。这样一来……就错得很离谱了。

      但是这道题跟错排的关系依然是很大的。如果还不了解错排,可以参见我的另一篇博客「错位排列及有关例题」

        我们首先可以根据数字是否为-1,以及数字i是否被使用过,把给的数字$a[i]$分成几类:

        第一类,$a[i] = -1$ 且 数字$i$还没有被使用过(即数字$i$没有出现在给定的序列中),那么这个位置除了其位置本身对应的数字$i$以外,其他剩余的数字都可以填进来。

        第二类,$a[i] = -1$ 且 数字$i$已经被使用过了,那么任何剩余的数字都可以填进来而且不会影响错位排列,想填什么就填什么。

        第三类,$a[i] ≠ -1$ 且 数字$i$还没有被使用过,这种数字的个数应该和第一类相同,都是有限制的随便填。

        第四类,$a[i] ≠ -1$ 且 数字$i$已经被使用过了,这种东西用都没有,就当他们是垃圾就好了。

      首先我们可以统计出一类(或三类)数字的出现次数$y$,以及二类数字的出现次数$x$。我们只考虑二类数字可能组成的方案数,将有$x$个数字填到$x$个无限制的位置中,方案数就是$P_x^x$。

      下面正式开始DP。令$f[i]$表示加入$i$个一类数字后的方案数。因此很容易得到$f[0] = P_x^x,即 x!$

      下面开始状态转移。对于第$i$个一类数字,我们可以把他填入到无限制的二类数字的位置中,方案数是$x * f[i-1]$。剩余的就直接做错位排列即可。

    代码注意点:

      随手MOD

    Code

    /*By QiXingzhi*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    #define int ll
    const int N = 10010;
    const int INF = 1061109567;
    const int MOD = 1000000007;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
        return x * w;
    }
    int n,ans,x,y;
    int f[N],a[N],b[N];
    inline int JieCheng(int x){
        int res = 1;
        for(int i = 2; i <= x; ++i){
            res = (res * i) % MOD;
        }
        return res%MOD;
    }
    #undef int
    int main(){
    #define int ll
    //    freopen(".in","r",stdin);
        n = r;
        for(int i = 1; i <= n; ++i){
            a[i] = r;
            if(a[i] != -1){
                b[a[i]] = 1;
            }
        }
    //    for(int i = 1; i <= n; ++i){
    //        printf("%lld ",b[i]);
    //    }
        for(int i = 1; i <= n; ++i){
            if(a[i] == -1 && b[i] > 0){
                ++x;
            }
    //        printf("a[%lld] = %lld  b[%lld] = %lld
    ",i,a[i],i,b[i]);
            if(a[i] == -1 && b[i] == 0){
                ++y;
            }
        }
    //    printf("x = %lld  y = %lld
    ",x,y);
        f[0] = JieCheng(x);
        for(int i = 1; i <= y; ++i){
            f[i] = (x * f[i-1] + (i-1) * f[i-1]) % MOD;
            if(i > 1) f[i] = (f[i] + (i-1) * f[i-2]) % MOD;
        }
        printf("%lld",f[y]);
        return 0;
    }
  • 相关阅读:
    11.29第四天冲刺记录
    11.28第三天冲刺记录
    11.27第二天冲刺记录
    11.26冲刺第一天
    团队项目计划
    软件分析_csdn app
    第二次结对编程-字词短语统计
    结对编程
    20155217 《信息安全系统设计基础》week16课堂测试
    20155217 《信息安全系统设计基础》课程总结
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9317339.html
Copyright © 2011-2022 走看看