zoukankan      html  css  js  c++  java
  • 花(唯一分解定理+排列组合+快速幂)

    问题描述:
    商店里出售n种不同品种的花。为了装饰桌面,你打算买m支花回家。你觉得放两支一样的花很难看,因此每种品种的花最多买1支。求总共有几种不同的买花的方案?答案可能很大,输出答案mod p的值。
    输入格式:
    一行3个整数n,m,p,意义如题所述。
    输出格式:
    一个整数,表示买花的方案数。
    输入输出样例1:
    输入:
    4 2 5
    输出:
    1
    输入输出样例1说明
    用数字1,2,3,4来表示花的种类的话,4种花里买各不相同的2支的方案有(1,2)、(1,3)、(1,4)、(2,3)、(2,4)、(3,4),共6种方案,模5后余数是1。
    数据范围:
    对于30%的数据,n,m≤10
    对于50%的数据,n,m≤1000
    对于80%的数据,1≤m≤n≤50,000
    对于100%的数据,1≤m≤n≤1,000,000,p≤1,000,000,000
    思路:
    组合数裸题,就是要求出c(n,m)%p
    由公式得:c(n,m)%p=!n*!m/!(n-m)%p
    首先会想到化简,分子分母能约的约掉,但是剩下的乘起来会爆(数据有点大。。。),这时候取模的话,答案显然是错误的,因为涉及到了除法,所以这种方案不可行!
    然后会想到费马小定理,求出逆元,进而得出答案,显然当p为合数是无解!
    最后无奈,分子分母分解质因数,然后约分,最后计算答案,加剪枝(否则80分,超时!)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define lon long long
    using namespace std;
    const int maxn=1000010;
    int n,m,p,ans=1,sum,a[maxn],prime[maxn],P[maxn];
    bool flag[maxn];
    void prepare()
    {
        for(int i=2;i<=1000000;i++)
        if(!flag[i])
        {
            prime[++sum]=i;
            P[i]=sum;
            for(int j=i+i;j<=1000000;j+=i)
            flag[j]=1;
        }
    }
    void work1(int x)
    {
        for(int i=1;i<=sum;i++)
        {
            if(x%prime[i]==0)
            {
                int tmp=0;
                while(x%prime[i]==0)
                {
                    x=x/prime[i];
                    tmp++;
                }
                a[i]+=tmp;
            }
            if(x==1) break;
            if(!flag[x])//剪枝
            {
                a[P[x]]++;
                break;
            }
        }
    }
    void work2(int x)
    {
        for(int i=1;i<=sum;i++)
        {
            if(x%prime[i]==0)
            {
                int tmp=0;
                while(x%prime[i]==0)
                {
                    x=x/prime[i];
                    tmp++;
                }
                a[i]-=tmp;
            }
            if(x==1) break;
            if(!flag[x])//剪枝
            {
                a[P[x]]--;
                break;
            }
        }
    }
    lon quick_power(lon x,lon y,lon z)//快速幂
    {
        lon tmp=1;
        while(y)
        {
            if(y&1)
            tmp=tmp*x%z;
            x=x*x%z;
            y>>=1;
        }
        return tmp;
    }
    int main()
    {
        cin>>n>>m>>p;
        prepare();//筛出素数,顺便预处理质因数分解
        for(int i=2;i<=n;i++)//对!n质因数分解,作为分子
        work1(i);
        for(int i=2;i<=m;i++)//对!m质因数分解,作为分母
        work2(i);
        for(int i=2;i<=n-m;i++)//对!(n-m)质因数分解,作为分母
        work2(i);
        for(int i=1;i<=sum;i++)
        if(a[i])
        ans=ans*quick_power(prime[i],a[i],p)%p;
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    用js获取当前页面的url
    innerHTML 和 innertext 以及 outerHTML
    scrollWidth,clientWidth与offsetWidth的区别
    top、postop、scrolltop、offsetTop、scrollHeight、offsetHeight、clientHeight
    两个文字向上滚动案列
    mysql 经典案例
    学习笔记11
    顺时针打印矩阵
    重建二叉树
    镜像二叉树
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070922.html
Copyright © 2011-2022 走看看