暑训day1 组合数学&概率期望

署训的第一天也是我正式作为成为一名Acmer的第一天。
未来的路还很长,还有很多坎要一步一步跨过去,立个flag:结果不重要,坚持下去就好。

做一下今天的知识点总结

  1. 加法原理&乘法原理
  2. 容斥原理
  3. 概率及数学期望
  4. (群)置换的一些概念(晕~

下面是一些有趣的题目
A(51 Nod 1383)
题目大意:将一个整数利用二进制性质划分为多个2的幂相加,问有多少种方案。
这是一个基础的计数问题,也是我第一次遇到的所谓计数dp的题。而实际上仔细考虑任何一个方案都可以划分为含有m个2^0和k个2^n(n>0).
显然
奇数时,num[i]=num[i-1]
偶数时,num[i]=num[i-1]+num[i/2] (通过划分为子问题来继续求解)

B Permutations(poj2369)
置换,取最小公倍数即可。

C Invoker (hdu3923)
题目大意:有n个技能,环状手链上有m个装填技能的凹槽,每一种组合方式都可以产生新的技能,且旋转相同或翻转相同的组合情况算作一同种组合,问有多少种技能。
超强的polya(由Burnside引理证明)计数原理:等价类的个数等于所有置换f的C(f)=k^m(f)的平均数(C(f)指对于一个置换f的不动点个数,m(f)指置换f的循环节个数),主要解决染色问题。(训练指南有详解)
代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const long long mod=1e9+7;
long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}
long long pow_mod(long long a,long long b)
{
    long long s=1;
    while(b)
    {
        if(b&1)
            s=(s*a)%mod;
        a=(a*a)%mod;
        b=b>>1;
    }
    return s;
}
long long polya(long long m,long long n)
{
    long long i,ans=0;
    for(i=1;i<=n;i++)
        ans+=pow_mod(m,gcd(i,n));

    if(n&1)ans+=n*pow_mod(m,n/2+1);
    else ans+=n/2*pow_mod(m,n/2)+n/2*pow_mod(m,n/2+1);

    ans=ans%mod*pow_mod(2*n,mod-2)%mod;//费马小定理(除法取模不满足结合律)inv(a)=pow(a,p-2)%p 
    return ans;
}
int main()
{
    int T,m,n,k=1;
   scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        printf("Case #%d: ",k++);
        printf("%lld\n",polya(n,m));
    }
    return 0;
}

注意旋转和翻转均要考虑对称性
旋转:所有循环长度相同,共有gcd(i,n)个循环,则这些置换的不动点总数为
a= i = 0 n 1 t g c d ( i , n )
翻转:对n分类讨论
奇,n条对称轴,共(n+1)/2个循环,不动点数b= n t n + 1 2
偶,有两种对称轴,不动点数b= n 2 ( t n 2 + 1 + t n 2 )

D Aeroplane chess(hdu4405)
hhhh做的第一道概率dp(计算期望)
注意这道从后往前推(好像一般都是这样)
代码

#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100050
int vis[maxn];
double dp[maxn];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    {
        memset(dp,0,sizeof(dp));
        memset(vis,-1,sizeof(vis));
        for(int i=0;i<m;++i)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            vis[a]=b;
        }
        for(int i=n-1;i>=0;--i)
        {
            if(vis[i]==-1)
            {
                for(int j=1;j<=6;j++)
                dp[i]+=1.0/6.0*dp[i+j];

                dp[i]+=1.0;
            }
            else
            dp[i]=dp[vis[i]];
        }
        printf("%.4lf\n",dp[0]);    
    }
    return 0;
}

E - 有趣的数列(bzoj1485)
“查”出来的最后一道(疯狂查资料,背结论,相信以后就会明白的~)附hzwer大神详解
卡特兰数直接套结论,记住一个公式 F(n)=C(2*n,n)/(n+1)
代码

#include<iostream>
using namespace std;
unsigned long int binomialCoeff(unsigned int n, unsigned int k)
{
    unsigned long int res = 1;


    if (k > n - k)
        k = n - k;


    for (int i = 0; i < k; ++i)
    {
        res *= (n - i);
        res /= (i + 1);
    }

    return res;
}
unsigned long int catalan(unsigned int n)
{

    unsigned long int c = binomialCoeff(2*n, n);


    return c/(n+1);
}

int main()
{
    int n,p;
    cin>>n>>p;
        cout << catalan(n)%p <<endl;
    return 0;
}

第一天只能水这几道(哇~的一声哭出来
有空再看看讲了的莫比乌斯函数作容斥系数????:同理因子容斥。所有非1的数可以分解成素数的乘积,如果题目能转化成有关纯素数计数的问题,可以用此划分。
还有死活不会求实现的FFT/NTT

毕竟第一天嘛,继续努力!

猜你喜欢

转载自blog.csdn.net/qq_40538328/article/details/81433297