CF340E Iahub and Permutations

(洛谷)题目链接

Solution

统计所有可能的放法,减去不合法情况。

设一共有 (num) 个位置缺失,其中有 (q) 个位置可能不合法。

枚举 (i) ((1≤i≤q)),表示当前有 (i) 个位置不合法。则有 (C(i,q)) 种取法,剩下的数有 ((num-i)!) 种排列方式。注意在组合数时除法要用乘法逆元来代替。

得到公式:(ans+=(-1)^i*C(i,q)*(num-i)!) ((1≤i≤q))

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
 
const int N = 2333, mod = 1e9 + 7;
LL n, ans, q = 0, num = 0, a[N], f[N], inv[N], vis[N];
 
LL poww(LL b, LL p)
{
    LL res = 1;
    while(p)
    {
        if(p & 1) res = (res * b) % mod;
        b = (b * b) % mod;
        p >>= 1;
    }
    return res % mod;
}
LL C(LL x, LL y) { return ((f[x] * inv[y]) % mod * inv[x - y]) % mod; }
 
int main()
{
    scanf("%lld", &n);
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        if(a[i] == -1) num++;
        else vis[a[i]] = 1;
    }
    for(int i = 1; i <= n; i++)
        if(a[i] == -1 && vis[i] == 0) q++;
    f[0] = 1;
    for(int i = 1; i <= n; i++)
        f[i] = (f[i - 1] * i) % mod;
    inv[n] = poww(f[n], mod - 2);
    for(int i = n - 1; i >= 1; i--)
        inv[i] = inv[i + 1] * (i + 1) % mod;
    inv[0] = 1;
    ans = f[num];
    for(int i = 1; i <= q; i++)
        ans = (ans + ((poww(-1, i & 1) * C(q, i)) % mod * f[num - i]) % mod) % mod;
    while(ans < 0) ans += mod;
    printf("%lld", ans % mod);
    return 0;
}
原文地址:https://www.cnblogs.com/Andy-park/p/13432191.html