Codeforces E. Iahub and Permutations 题解存档

E. Iahub and Permutations

题目链接:https://codeforces.com/problemset/problem/340/E
主要是mark一下大佬们的题解和笔记,以方便日后复习

此题有两种做法:

  1. 容斥原理
    原理:http://www.cppblog.com/vici/archive/2011/09/05/155103.aspx
    (我反正是不懂)
  2. DP(错位排列)
    错位排列的原理:https://www.cnblogs.com/qixingzhi/p/9285830.html
    本题题解:https://www.cnblogs.com/qixingzhi/p/9317339.html

个人总结:

  1. 先理解此状态转移方程的含义:\(f[i]=(i−1)∗(f[i−1]+f[i−2])\)
  2. 可以根据数字是否为-1,以及数字i是否被使用过,把给的数字a[i]分成4类

My Code

注意一些细节:

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 2005, mod = 1e9 + 7;
int n, x, y;
int a[N], f[N];
bool vis[N]; //有无被使用过

//求阶乘
int mul (int x) {
    int res = 1;
    for (int i = 2; i <= x; i ++)
        res = (res * i) % mod;
    return res;
}

signed main () {

    cin >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        if (a[i] != -1)
            vis[a[i]] = true;
    }
        
    for (int i = 1; i <= n; i ++) {
        if (a[i] == -1 && vis[i])
            x ++;
        if (a[i] == -1 && !vis[i]) //a[i]!=-1的时候你也不需要操作啊!!
            y ++;
    }

    f[0] = mul (x);
    for (int i = 1; i <= y; i ++) {
        f[i] = ((x + i - 1) * f[i - 1]) % mod; //算上前面那一段
        if (i > 1) //避免i-2为负数
            f[i] = (f[i] + (i - 1) * f[i  -2]) % mod;
    }

    cout << f[y] << endl;

}
//情况:
//1. a[i]=-1,i未被使用过——y
//2. a[i]=-1,i已被使用过——x
//3. a[i]!=-1,i未被使用过——y
//4. a[i]!=-1,i已被使用过——0

偏个题:欧拉函数 https://www.cnblogs.com/qixingzhi/p/9314003.html

posted @ 2022-05-03 22:44  Sakana~  阅读(37)  评论(0编辑  收藏  举报