zoukankan      html  css  js  c++  java
  • noip模拟赛 花

    【问题描述】
    商店里出售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。

    【输入输出样例2】
    见选手目录下的flower / flower2.in与flower / flower2.out

    【数据范围】
    对于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

    分析:有点技巧的数学题。n,m很大,不能递推来求,p可能是个合数,不能求逆元,唯一的方法就是尽量把C(n,m)给缩小.因为C(n,m)可以表示为一个除法式子,将其变小的一般方法就是约分,对每个数分解质因数,在次数上加加减减就可以了,最后套上快速幂.

          直接上裸的会T,需要一些优化.筛法用上线性筛,在分解质因数的时候只分解没有出现过的,分解的过程中如果要分解的数是一个质数了就要退出.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    ll n, m, p, cnt, prime[1000010], ans = 1, tot[1000010];
    bool vis[1000010];
    
    void init()
    {
        for (ll i = 2; i <= 1000000; i++)
        {
            if (!vis[i])
                prime[++cnt] = i;
            for (int j = 1; j <= cnt; j++)
            {
                if (i * prime[j] > 1000000)
                    break;
                vis[i * prime[j]] = 1;
                if (i % prime[j] == 0)
                    break;
            }
        }
    }
    
    void work(ll p,int x)
    {
        ll t = p;
        if (!vis[p])
        {
            tot[p] += x;
            return;
        }
        for (int i = 1;prime[i] * prime[i] <= t && i <= cnt; i++)
        {
            if (p == 1)
                return;
            if (p % prime[i] == 0)
            {
                int tott = 0;
                while (p % prime[i] == 0)
                {
                    p /= prime[i];
                    tott++;
                }
                tot[prime[i]] += tott * x;
            }
            if (!vis[p])
            {
                tot[p] += x;
                return;
            }
        }
        if (x)
            tot[p] += x;
    }
    
    ll qpow(ll a, ll b, ll mod)
    {
        ll res = 1;
        while (b)
        {
            if (b & 1)
                res = (res * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return res;
    }
    
    int main()
    {
        init();
        scanf("%lld%lld%lld", &n, &m, &p);
        for (ll i = n; i >= m + 1; i--)
            work(i, 1);
        for (ll i = 1; i <= n - m; i++)
            work(i, -1);
        for (ll i = 1; i <= cnt; i++)
            if (tot[prime[i]])
                ans = (ans * qpow(prime[i], tot[prime[i]], p)) % p;
        printf("%lld
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    小程序登录页面
    小程序环境搭建
    js闭包
    作用域和作用域链及预解析
    高阶函数
    在.net core项目中,增加gulp打包任务
    阿里云部署docker-swarm 内网问题
    .net identity scaffold
    c#中对XML反序列化
    c# Reactive Extension中的FromEventPattern和FromEvent
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7729121.html
Copyright © 2011-2022 走看看