Codeforces Round #198 (Div. 2)E题解

E. Iahub and Permutations

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 a1, a2, ..., 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).

题意:给定一个数列,如果是-1则代表需要填,否则是一个固定数,

在所有-1处填入数字,使得得到的数列为n的一个排列,且各个位置的数与该位置的坐标编号不相同,求mod(1e9 + 7)意义下的方案数

似乎是道没什么新意的组合题,非常容易的想出随便容斥一下就好了?
显然发现排列这个性质十分弱,但编号不同的性质非常的强
考虑从排列入手,对于一个排列,我们去处理编号的问题
先不考虑编号问题,那么排列数实际上就是(-1的个数)k!,然后我们考虑去掉有一个编号重复的情况,这样有两个编号重复的情况就会被多减,然后加回去...以此类推大力容斥
对于处理有p个编号重复的情况,实际上就是选出个编号的方案数f*(k - p)!
考虑细节,需要先知道有哪些位置可以重复,由于题目求方案数的特性,我们不用在意哪个位置可以重复,只要考虑有多少个位置可以重复,这个东西可以非常快速的预处理O(n)出,再考虑选择方案数的问题,这个东西很显然是个组合数,预处理一下就好了,
最后O(n^2)容斥求解就好了

#include <bits/stdc++.h>
using namespace std;

const long long Yn = 1e9 + 7;

bool flag[2010], num[2010];
long long power[2010], s[2010], C[2010];

long long Pow(long long a, long long b, long long mod) {
    long long ans = 1;
    while (b) {
        if (b & 1) (ans *= a) %= mod;
        b /= 2;
        (a *= a) %= mod;
    }
    return ans;
}

int main() {
    
    long long ans = 0;
    int n, sum = 0, sum1 = 0;
    cin >> n;
    memset(flag, 0 ,sizeof flag);
    for (int i = 1; i <= n; ++i) {
        cin >> s[i];
        if (s[i] > 0)
            flag[s[i]] = 1;
        else sum ++, num[i] = 1;
    }

    for (int i = 1; i <= n; ++i)
        if ((!flag[i]) && num[i]) sum1 ++;

    power[0] = 1;
    for (int i = 1; i <= n; ++i)
        power[i] = (power[i - 1] * i) % Yn;

    C[0] = 1;
    for (long long i = 1; i <= sum1; ++i) {
        (C[i] = C[i - 1] * (sum1 - i + 1)) %= Yn;
        (C[i] *= Pow(i, Yn - 2, Yn)) %= Yn;
    }

    int fff = 1;
    for (int i = 0; i <= sum1; ++i)
        (ans += (fff * power[sum - i] % Yn * C[i] % Yn + Yn)) %= Yn, fff *= -1;

    cout << (ans % Yn + Yn) % Yn << endl;

    return 0;

}
View Code
原文地址:https://www.cnblogs.com/logic-yzf/p/7576376.html