数学专题小记

来源:互联网 发布:淘宝网石头鱼大码女装 编辑:程序博客网 时间:2024/06/07 03:31

【二项式反演】

二项式反演公式:
f(n)=ni=0(ni)g(i)
g(n)=ni=0(1)ni(ni)g(i)

【例题1.】

提交地址:https://www.nowcoder.com/acm/contest/10/C

题意:
给你一排n个格子,m种颜色,让你填色,相邻不同色。问你恰好使用k种颜色的方案数。(n,m109,1k106
思路:
定义f(m):最多可用m种颜色涂色n个格子且相邻的不同色的方案数。则f(m)=m(m1)n1.
定义g(x):恰好使用x种颜色涂色n个格子切相邻的不同色的方案数。
f(m)=m(m1)n1=mx=1(mx)g(x).
利用二项式反演公式可得g(m)=mx=1(1)mi(mx)f(x)
显然,我们所求的东西就是g(k)=kx=1(1)ki(kx)f(x)

【鸽巢原理】

鸽巢原理(抽屉原理)若把n个物体放在n - 1个抽屉中,至少有一个抽屉中放了两个物体。

【例题1 Gym - 101291I.Mismatched Socks】

题意:
给你n种不同的袜子的各自的数量。问你最多能配几对不同的袜子。(n1000ki1e9
思路:
雀巢原理?统计一下最多的袜子有几双,剩下的袜子有几双,其实就是一个雀巢原理的穿插的感觉吧。其实复杂度可以O(n)的,只是看看这数据好水,才1000,懒得写max了,直接用堆了。
【Source】2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)

#include <bits/stdc++.h>using namespace std;typedef long long LL;int main(){    int n;    scanf("%d", &n);    LL preSum = 0;    priority_queue<int>que;    for(int i =0; i <n ;i++)    {        int x;        scanf("%d", &x);        que.push(x);        preSum += x;    }    int maxx = que.top();    preSum -= maxx;    if(preSum >= maxx) printf("%lld\n", (preSum + maxx) / 2);    else printf("%lld\n", preSum);    return 0;}

【概率&&期望】

【Gym - 101291K.Six Sides】

题意:
有俩骰子,六个面的,然后告诉你他们各自面上分别是多少数值。一人扔一次,点数大的赢。如果相同,再扔一次,直到分出胜负。问你第一个人赢的概率。
思路:
推个公式就完。p是第一个人赢的概率,q是平局的概率,那么
ans=k=0p×qk
【Source】2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)

    #include <bits/stdc++.h>      using namespace std;      int main()      {          int a[6], b[6];          for(int i = 0; i < 6; i++)  scanf("%d", &a[i]);        for(int i = 0; i < 6; i++)  scanf("%d", &b[i]);         int x = 0, y = 0;          for(int i = 0; i < 6;i ++)          {              for(int j = 0; j < 6; j++)              {                  if(a[i] > b[j]) x++;                  else if(a[i] == b[j])   y++;              }          }          double p = x / 36.0, q = y / 36.0;//p为player1胜的概率  q为平局概率          printf("%.5f\n", p / (1.0 - q));          return 0;      }  

【Gym - 101343 A. On The Way to Lucky Plaza】

题意:题意:有m个超市 每个超市买到东西的概率为P 且只能买一个东西。问在第n个超市买到第k个东西的概率为多少。假设概率是p/q 那么输出x 使得 x*q=p(mod 1e9+7)

思路:随手推个概率公式吧。trick点就是读入的时候*1000,需要调一调精度啊?。+0.5什么的。

#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 5;const int mod = 1e9 + 7;typedef long long LL;LL fac[maxn], invf[maxn];LL quickPow(LL a, LL b, LL Mod){    LL ret = 1;    a %= mod;    while(b)    {        if(b & 1)   ret = ret * a % Mod;        b >>= 1;        a = (a * a) % Mod;    }    return ret;}void init(){    int limit = 100000;    fac[0] = 1;    for(int i = 1; i <= limit; i++)   fac[i] = i * fac[i - 1] % mod;    invf[limit] = quickPow(fac[limit], mod - 2, mod);    for(int i = limit - 1; i >= 0; i --) invf[i] = invf[i + 1] * (i + 1) % mod;}LL inv(LL x){    return quickPow(x, mod-2, mod);}LL C(LL n, LL m){    LL ret = 0;    ret = fac[n] * invf[m] % mod * invf[n - m] % mod;    return ret;}int main(){    init();    int m, n, k;    double temp;    scanf("%d%d%d", &m, &n, &k);    scanf("%lf", &temp);    long long p = temp * 1000 + 0.5;    long long q = 1000;    if(k > n)   puts("0");    else if(n > m)  puts("0");    else    {        if(p == 0)        {            puts("0");            return 0;        }        else if(p == 1000)        {            if(n == k)  puts("1");            else puts("0");            return 0;        }        LL t2 = quickPow(p, k-1, mod) * inv(quickPow(q, k-1, mod)) % mod;        LL t3 = quickPow(q-p,n-k,mod) * inv(quickPow(q, n-k, mod)) % mod;        LL ans = p * inv(q) % mod * C(n-1,k-1) % mod * t2 % mod * t3 % mod;        cout << ans << endl;    }    return 0;}

【source】http://codeforces.com/gym/101343/problem/A

【组合数学】

【第二类斯特林数】

第二类Stirling数的意义是:S(n,k)表示将n个物体划分成k个无序集合的方法。
S[i][j]:前i个物品划分到j个集合中。S[i][j] = j * S[i - 1][j] + S[i - 1][j - 1];
【例题1 Gym 101147G - The Galactic Olympics】

题意:n场不同的比赛,派k个人去,一个人可以参加多场比赛且至少参加一场,每场比赛只能且必须要有一个人参加,问方案数。(n1e3k1e6
思路:首先,人肯定比赛多的时候,肯定是0。剩下就是情况就是一个第二类斯特林数S[n][k]k!了。

#include <bits/stdc++.h>using namespace std;const int maxn = 1e3 + 5;const int mod = 1e9 + 7;typedef long long LL;LL fac[maxn];LL dp[maxn][maxn];int main(){    freopen("galactic.in", "r", stdin);    for(int i = 0; i <= 1000; i++)   dp[i][i] = 1;    for(int i = 2; i <= 1000; i++)    {        for(int j = 1; j < i; j++)        {            dp[i][j] = 1LL * j * dp[i - 1][j] % mod + dp[i - 1][j - 1];            dp[i][j] %= mod;        }    }    fac[0] = 1;    for(int i = 1; i <= 1000; i++)  fac[i] = fac[i - 1] * i % mod;    int T;    scanf("%d", &T);    while(T--)    {        int games, people;        scanf("%d%d", &games, &people);        if(games < people)   puts("0");        else    printf("%lld\n", dp[games][people] * fac[people] % mod);    }    return 0;}
原创粉丝点击