bzoj4870 【六省联考2017】 组合数问题

http://www.elijahqi.win/archives/531
题目描述

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

Cnm=n!m!(n−m)!C_n^m = \frac{n!}{m!(n-m)!}C​n​m​​=​m!(n−m)!​​n!​​

其中 n! = 1 × 2 × · · · × n。(特别的,当 n = 0 时, n! = 1 ,当 m > n 时, Cnm=0C_n^m =0C​n​m​​=0)

小葱在 NOIP 的时候学习了 CijC_i^jC​i​j​​ 和 k 的倍数关系,现在他想更进一步,研究更多关于组合数的性质。小葱发现, CijC_i^jC​i​j​​ 是否是 k 的倍数,取决于 CijmodkC_i^j mod k C​i​j​​modk是否等于 0,这个神奇的性质引发了小葱对 mod 运算(取余数)的兴趣。现在小葱选择了是四个整数n; p; k; r,小葱现在希望知道

∑i=0infCnkik+rmodp\sum_{i=0}^{\inf} C_{nk}^{ik+r} mod p∑​i=0​inf​​C​nk​ik+r​​modp

的值。

输入输出格式

输入格式:

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

输出格式:

一行一个整数代表答案。

输入输出样例

输入样例#1:

2 10007 2 0
输出样例#1:

8
输入样例#2:

20 10007 20 0
输出样例#2:

176
说明

• 对于 30% 的测试点, 1 ≤ n; k ≤ 30, p 是质数;

• 对于另外 5% 的测试点, p = 2;

• 对于另外 5% 的测试点, k = 1;

• 对于另外 10% 的测试点, k = 2;

• 对于另外 15% 的测试点, 1 ≤ n ≤ 10^3; 1 ≤ k ≤ 50, p 是质数;

• 对于另外 15% 的测试点, 1 ≤ n × k ≤ 10^6, p 是质数;

• 对于另外 10% 的测试点, 1 ≤ n ≤ 10^9; 1 ≤ k ≤ 50, p 是质数;

• 对于 100% 的测试点, 1 ≤ n ≤ 10^9; 0 ≤ r < k ≤ 50; 2 ≤ p ≤ 2^30 − 1。

需要看出来这个公式的实际意义,因为r

#include<cstdio>
#include<cstring>
#define N 55
struct matrix{
    int f[N][N],l,c;
}ans,m;
int n,p,k,r;
inline matrix multiply(matrix a,matrix b){
    matrix c;memset(c.f,0,sizeof(c.f));
    c.l=a.l;c.c=b.c;
    for (int i=0;i<a.l;++i)
        for (int j=0;j<b.c;++j)
            for (int z=0;z<a.c;++z){
                c.f[i][j]=((long long) a.f[i][z]*b.f[z][j]%p+c.f[i][j])%p;
            }
    return c;
}
int main(){
//  freopen("3746.in","r",stdin);
    scanf("%d%d%d%d",&n,&p,&k,&r);long long t=(long long)n*k;
    m.c=m.l=k;
    for (int i=0;i<k;++i) m.f[i][i]++,m.f[(i-1+k)%k][i]++;
    ans.c=k;ans.l=k;
    for (int i=0;i<k;++i) ans.f[i][i]=1;
    for (;t;t>>=1,m=multiply(m,m)){
        if (t&1) ans=multiply(m,ans);
    }
    printf("%d",ans.f[0][r]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值