清北学堂 day6 花

1.花
flower.cpp/c/pas
【 问题描述】
商店里出售 n 种不同品种的花。为了装饰桌面,你打算买 m 支花回家。你觉得放两支一
样的花很难看,因此每种品种的花最多买 1 支。求总共有几种不同的买花的方案? 答案可能
很大,输出答案 mod p 的值。
【 输入格式】
一行 3 个整数 n, m, p, 意义如题所述。
【 输出格式】
一个整数,表示买花的方案数。
【输入输出样例 1

flower.in flower.out
4 2 5 1


见选手目录下的 flower / flower1.in flower / flower1.out
【输入输出样例 1 说明】
用数字 1,2,3,4 来表示花的种类的话,4 种花里买各不相同的 2 支的方案有(1,2)、(1,3)、
(1,4)、 (2,3)、 (2,4)、 (3,4), 共 6 种方案, 模 5 后余数是 1。
【输入输出样例 2
见选手目录下的 flower / flower2.in flower / flower2.out
【 数据范围】
对于 30%的数据, n,m10
对于 50%的数据, n,m1000
对于 80%的数据, 1mn50,000
对于 100%的数据, 1mn1,000,000, p1,000,000,000

 

解:100分:运用组合数公式:C(n,m)=n!/(m!*(n-m)!)

因为范围较大,所以进行质因数分解以约分,先打出质数表,最后直接寻找剩余质数并进行乘法取模即可;(必要时可使用快速幂与快速加)。

开 long #include<iostream>

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define man 1000010
#define sc(x) scanf("%lld",&x)
#define mem(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;
ll used[man],prime[man],tot=0,aa=1;
bool isp[man];
int  n,m,p;
inline void mkp(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(!isp[i])
        {    prime[++tot]=i;
            }
        for(int j=1;j<=tot&&i*prime[j]<=x;j++)
        {
            isp[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
            }
        }
    }
void calc1(int x)//n
{    
    int ans=x;
    for(int i=1;i<=tot;i++)
    {    
        if(ans%prime[i]==0)
        {
            int t=0;
            while(ans%prime[i]==0)
            {
                ans=ans/prime[i];
                t++;
                }
            used[prime[i]]+=t;    
            }
        if(!isp[ans])
        {    used[ans]++;
            ans=1;
            }
        if(ans==1)
            break;
        }
    }
void calc2(int x)//m&(n-m)
{    
    int ans=x;
    for(int i=1;i<=tot;i++)
    {
        if(ans%prime[i]==0)
        {
            int t=0;
            while(ans%prime[i]==0)
            {
                ans=ans/prime[i];
                t++;
                }
            used[prime[i]]-=t;    
            }
        if(!isp[ans])
        {    used[ans]--;
            break;
            }
        if(ans==1)
            break;
        }
    }
ll badd(ll a,ll b,ll c)//快速加
{
    ll ans=0,bas=a;
    while(b)
    {
        if(b&1) ans=(ans+bas)%p;
        bas=(bas+bas)%p;
        b>>=1;
        }
    return ans;
    }
ll bpow(ll a,ll b,ll c)//快速幂
{
    int  ans=1,bas=a;
    while(b)
    {
        if(b&1) ans=(ans*(bas%p))%p;
        bas=((bas%p)*(bas%p))%p;
        b>>=1;
        }
    return ans;
    }
int main()
{    freopen("flower.in","r",stdin);
    freopen("flower.out","w",stdout);
    mem(prime);mem(used);mem(isp);
    sc(n);sc(m);sc(p);
    mkp(n);
    for(int i=2;i<=n;i++)//对n!质因数分解
    calc1(i);
    for(int i=2;i<=m;i++)//对m!质因数分解
    calc2(i);
    for(int i=2;i<=n-m;i++)//对(n-m)!质因数分解
    calc2(i);
    for(int i=1;i<=tot;i++)
    {    
        if(used[prime[i]]>0)
        {    
            aa=badd(aa,bpow(prime[i],used[prime[i]],p),p);
            }
        }
    printf("%lld\n",aa);
    return 0;
    }

 

posted @ 2017-08-27 17:51  Slager_Z  阅读(169)  评论(0编辑  收藏  举报
博客园 首页 私信博主 显示目录 隐藏目录 管理 动画