zoukankan      html  css  js  c++  java
  • Codeforces Round #198 (Div. 2) E. Iahub and Permutations —— 容斥原理

    题目链接:http://codeforces.com/contest/340/problem/E


    E. Iahub and Permutations
    time limit per test
    1 second
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Iahub is so happy about inventing bubble sort graphs that he's staying all day long at the office and writing permutations. Iahubina is angry that she is no more important for Iahub. When Iahub goes away, Iahubina comes to his office and sabotage his research work.

    The girl finds an important permutation for the research. The permutation contains n distinct integers a1a2, ..., an (1 ≤ ai ≤ n). She replaces some of permutation elements with -1 value as a revenge.

    When Iahub finds out his important permutation is broken, he tries to recover it. The only thing he remembers about the permutation is it didn't have any fixed point. A fixed point for a permutation is an element ak which has value equal to k (ak = k). Your job is to proof to Iahub that trying to recover it is not a good idea. Output the number of permutations which could be originally Iahub's important permutation, modulo 1000000007 (109 + 7).

    Input

    The first line contains integer n (2 ≤ n ≤ 2000). On the second line, there are n integers, representing Iahub's important permutation after Iahubina replaces some values with -1.

    It's guaranteed that there are no fixed points in the given permutation. Also, the given sequence contains at least two numbers -1 and each positive number occurs in the sequence at most once. It's guaranteed that there is at least one suitable permutation.

    Output

    Output a single integer, the number of ways Iahub could recover his permutation, modulo 1000000007 (109 + 7).

    Examples
    input
    5
    -1 -1 4 3 -1
    
    output
    2
    
    Note

    For the first test example there are two permutations with no fixed points are [2, 5, 4, 3, 1] and [5, 1, 4, 3, 2]. Any other permutation would have at least one fixed point.

    题意:

    给出大小为n的序列,如果a[i] = k (1<=k<=n),则表明i位置被数字k占领了,如果a[i] = -1,则表明这个数字没有被占领。问:在这种情况下,有多少种错排方式?(题目输入保证有错排)

    题解:

    1.利用容斥原理计算出非法排列的个数, 非法排列即为至少有一个数是放在原位的, 即a[i] = i。

    2.用全排列的个数减去非法排列的个数,即为答案。


    容斥原理分析:

    1.设m为空位数, k为可以放回原位的个数。

    2.枚举可以放回原位的数的个数i,然后再对剩下可放的数进行排列。通式: C(k, i)*A(m-i, m-i):

    2.1.当a需要放回原位时(其他有没放回原位不考虑), 那么剩下的数的排列有A(m-1, m-1); 对于 b、c等等, 也如此, 所以总数为C(k,1) * A(m-1, m-1); 根据容斥原理,奇数个时加上。

    2.2.当a和b都需要放回原位时(其他有没放回原位不考虑), 那么剩下的数的排列有A(m-2, m-2);对于其他的两两组合也是一样, 所以总数为 C(k,2) * A(m-2, m-2); 根据容斥原理, 偶数个时减去。

    2.3.  3个、4个、5个 …… k个。奇数个时加, 偶数个时减。


    易错点:

    1.凡是带有除法的式子, 都不能直接求模。

    2.求模时, 若是加上负数, 需要: ans = (ans + mod)% mod 。



    代码如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const double eps = 1e-6;
     5 const int INF = 2e9;
     6 const LL LNF = 9e18;
     7 const int mod = 1e9+7;
     8 const int maxn = 2e3+10;
     9 
    10 bool val[maxn], pos[maxn];
    11 LL C[maxn][maxn], A[maxn];
    12 
    13 void init()
    14 {
    15     A[0] = 1; C[0][0] = 1;
    16     for(int i = 1; i<maxn; i++)
    17     {
    18         A[i] = (1LL*i*A[i-1])%mod;
    19         C[i][0] = 1;
    20         for(int j = 1; j<=i; j++)
    21             C[i][j] = (C[i-1][j-1] + C[i-1][j])%mod;
    22     }
    23 }
    24 
    25 int main()
    26 {
    27     init();
    28     int n, m, k;
    29     while(scanf("%d",&n)!=EOF)
    30     {
    31         for(int i = 1; i<=n; i++)
    32         {
    33             int x;
    34             scanf("%d",&x);
    35             if(x!=-1)
    36                 val[x] = pos[i] = 1;
    37         }
    38 
    39         k = m = 0;
    40         for(int i = 1; i<=n; i++)
    41         {
    42             if(!pos[i]) m++;
    43             if(!pos[i] && !val[i]) k++;
    44         }
    45 
    46         LL ans = A[m];
    47         for(int i = 1; i<=k; i++)
    48         {
    49             LL tmp = (1LL*C[k][i]*A[m-i])%mod;
    50             ans -= (i&1)?tmp:-tmp;  //容斥原理
    51             ans = (ans+mod)%mod;
    52         }
    53         cout<<ans<<endl;
    54     }
    55 }
    View Code



  • 相关阅读:
    趋势线突破有效的标志 武胜
    jira 试用license
    Jmeter使用指南
    linux c mysql 编程
    apache module 读取配置文件
    solr 中文分词 mmseg4j 使用例子 ,NGramTokenizerFactory
    使用CTabCtrl控件实现属性页功能
    linux 命令
    vc++2008 采用GSoap访问 WebService
    apr 编程demo出错。
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538671.html
Copyright © 2011-2022 走看看