D、Homework of PE 容斥原理

https://scut.online/p/113

终于想懂了这个容斥,

华工4月23号校赛,
考虑总的所有情况,设1---n里面含有质数的个数为all,需要固定m个质数。那么有

totSum = C(all, m) * (n - m)!,就是在all个质数里面,任意选m个出来固定,剩下的全排。

但是算多了,因为还有一些质数(不在那m个之内)也会被固定,

而且,考虑样例

5 1,

1 2 3 4 5

 


这个时候,先考虑任选m个出来固定,题目就是任选1个出来固定。剩下的全排

比如固定了2,剩下的全排,会产生,只固定了2,固定了2、3,固定了2、5,固定了2、3、5

比如固定了3,剩下的全排,会产生,只固定了3,固定了2、3,固定了3、5,固定了2、3、5

比如固定了5,剩下的全排,会产生,只固定了5,固定了2、5,固定了3、5,固定了2、3、5

那么只有第一列相加的才是正确答案。后面的要减去。

减去固定了两个的时候,

这个时候前面一个已经固定了,再枚举一个来固定,就是固定2个。所以固定(3, 2)和(2, 3)是不同的方案。

固定了(2, 3)时,会有,只固定2、3和固定了2、3、5

固定了(3, 2)时,会有,只固定3、2和固定了3、2、5

.....

等等。

减去这些后,会发现结果是ans - 3 * (固定了2、3、5),加回来就是了。

就是一个容斥,以后容斥要实打实写出来,毕竟不是大神。

哭~~~~

比赛没想到。刚才也想了很久,光想是不行的。要模拟。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>

bool check(int val) {
    int en = (int)sqrt(val);
    for (int i = 2; i <= en; ++i) {
        if (val % i == 0) return false;
    }
    return true;
}
const int MOD = 1e9 + 7;
LL fac[222];
LL quick_pow(LL a, LL b, LL MOD) {
    LL base = a % MOD;
    LL ans = 1;
    while (b) {
        if (b & 1) {
            ans = ans * base % MOD;
        }
        base = base * base % MOD;

        b >>= 1;
    }
    return ans;
}

LL C(LL n, LL m, LL MOD) {
    if (n < m) return 0;
    if (n == m) return 1 % MOD;
    LL ans1 = 1;
    LL ans2 = 1;
    LL mx = max(n - m, m);
    LL mi = n - mx;
    for (int i = 1; i <= mi; ++i) {
        ans1 = ans1 * (mx + i) %MOD;
        ans2 = ans2 * i % MOD;
    }
    return (ans1 * quick_pow(ans2, MOD - 2, MOD) % MOD);
}
int n, m;
void work() {
    fac[0] = 1;
    for (int i = 1; i <= 200; ++i) {
        fac[i] = fac[i - 1] * i % MOD;
    }
    int all = 0;
    for (int i = 2; i <= n; ++i) {
        all += check(i);
    }
    LL ans = C(all, m, MOD) * fac[n - m] % MOD;
//    cout << ans << endl;
    for (int i = 1; i <= all - m; ++i) {
        if (i & 1) {
            ans = (ans + MOD - C(all, m, MOD) * C(all - m, i, MOD) % MOD * fac[n - (m + i)] % MOD) % MOD;
        } else ans = (ans + C(all, m, MOD) * C(all - m, i, MOD) % MOD * fac[n - (m + i)] % MOD) % MOD;
    }
    cout << ans % MOD << endl;
}

int main() {
    #ifdef local
    freopen("data.txt", "r", stdin);
    #endif
    scanf("%d%d", &n, &m);
    work();
    return 0;
}
View Code

 

posted on 2017-04-25 14:00  stupid_one  阅读(264)  评论(0编辑  收藏  举报

导航