zoukankan      html  css  js  c++  java
  • loj #2143. 「SHOI2017」组合数问题

    #2143. 「SHOI2017」组合数问题

     

    题目描述

    组合数 Cnmmathrm{C}_n^mCnm​​ 表示的是从 nnn 个互不相同的物品中选出 mmm 个物品的方案数。举个例子, 从 (1,2,3)(1, 2, 3)(1,2,3) 三个物品中选择两个物品可以有 (1,2)(1, 2)(1,2),(1,3)(1, 3)(1,3),(2,3)(2, 3)(2,3) 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 Cnmmathrm{C}_n^mCnm​​ 的一般公式:

    Cmn=n!m! (nm)!

    其中 n!=1×2×⋯×nn! = 1 imes 2 imes cdots imes nn!=1×2××n。(特别地,当 n=0n = 0n=0 时,n!=1n! = 1n!=1;当 m>nm > nm>n 时,Cnm=0mathrm{C}_n^m = 0Cnm​​=0。)

    小葱在 NOIP 的时候学习了 Cijmathrm{C}_i^jCij​​ 和 kkk 的倍数关系,现在他想更进一步,研究更多关于组合数的性质。小葱发现,Cijmathrm{C}_i^jCij​​ 是否是 kkk 的倍数,取决于 Cjimodk 是否等于 000,这个神奇的性质引发了小葱对 modmathrm{mod}mod 运算(取余数运算)的兴趣。现在小葱选择了是四个整数 n,p,k,rn, p, k, rn,p,k,r,他希望知道

    (i=0Cik+rnk)modp,

    (Crnk+Ck+rnk+C2k+rnk++C(n1)k+rnk+Cnk+rnk+)modp

    的值。

    输入格式

    第一行有四个整数 n,p,k,rn, p, k, rn,p,k,r,所有整数含义见问题描述。

    输出格式

    一行一个整数代表答案。

    样例

    样例输入 1

    2 10007 2 0

    样例输出 1

    8

    样例解释 1

    C40+C42+C44+⋯=1+6+1=8mathrm{C}_4^0 + mathrm{C}_4^2 + mathrm{C}_4^4 + cdots = 1 + 6 + 1 = 8C40​​+C42​​+C44​​+=1+6+1=8。

    样例输入 2

    20 10007 20 0

    样例输出 2

    176

    数据范围与提示

    对于 30%30\%30% 的测试点,1≤n,k≤301 leq n, k leq 301n,k30,ppp 是质数;
    对于另外 5%5\%5% 的测试点,p=2p = 2p=2;
    对于另外 5%5\%5% 的测试点,k=1k = 1k=1;
    对于另外 10%10\%10% 的测试点,k=2k = 2k=2;
    对于另外 15%15\%15% 的测试点,1≤n≤103,1≤k≤501 leq n leq 10^3, 1 leq k leq 501n103​​,1k50,ppp 是质数;
    对于另外 15%15\%15% 的测试点,1≤n×k≤1061 leq n imes k leq 10^61n×k106​​,ppp 是质数;
    对于另外 10%10\%10% 的测试点,1≤n≤109,1≤k≤501 leq n leq 10^9, 1 leq k leq 501n109​​,1k50,ppp 是质数;
    对于 100%100\%100% 的测试点,1≤n≤109,0≤r<k≤50,2≤p≤230−11 leq n leq 10^9, 0 leq r < k leq 50, 2 leq p leq 2^{30} - 11n109​​,0r<k50,2p230​​1。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int f[1000010][51],n,p,k,r;
    int main(){
        scanf("%d%d%d%d",&n,&p,&k,&r);
        f[0][0]=1;
        for(int i=1;i<=n*k;i++)
            for(int j=0;j<k;j++){
                if(j!=0)f[i][j]=(f[i-1][j]+f[i-1][j-1])%p;
                else f[i][j]=(f[i-1][j]+f[i-1][j+k-1])%p;
            }
        printf("%d",f[n*k][r]);
    }
    60分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int P,K,R;
    long long N;
    struct matrix{
        int n,m,a[51][51];
        matrix(){memset(a,0,sizeof(a));}
        matrix operator * (const matrix &c)const{
            matrix res;res.n=n;res.m=c.m;
            for(int i=0;i<n;i++)
                for(int j=0;j<c.m;j++)
                    for(int k=0;k<m;k++)
                        res.a[i][j]=(res.a[i][j]+1LL*a[i][k]*c.a[k][j]%P)%P;
            return res;
        }
    }a,b;
    void Pow(matrix x,long long y){
        while(y){
            if(y&1)
                a=a*x;
            x=x*x;
            y>>=1;
        }
    }
    int main(){
        cin>>N;
        scanf("%d%d%d",&P,&K,&R);
        N=1LL*N*K;
        a.n=1;a.m=K;a.a[0][0]=1;
        b.n=b.m=K;
        for(int i=0;i<K;i++)b.a[i][i]++,b.a[i][(i+1)%K]++;
        Pow(b,N);
        printf("%d",a.a[0][R]);
        return 0;
    }
    100分 矩阵快速幂优化dp
  • 相关阅读:
    Linux-命令-parted
    Linux-磁盘
    Linux-bash需要转意的字符
    Linux-命令-su-sudo-visudo
    Linux-命令-用户登录及日志查询
    Linux-练习-批量创建用户5密码长度
    250W电源带i7+GTX1080?
    ICMP type code 对应表(转)
    U盘FAT32转换NTFS格式
    Maxdos 9.3不能引导系统进入Maxdos
  • 原文地址:https://www.cnblogs.com/thmyl/p/8908173.html
Copyright © 2011-2022 走看看