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

  写数学题总是没有思路,还是太菜了。

  题目大意:给定n,p,k,r,你要求的是ΣC(nk,x)%p的值,其中x%k=r。n是1e9,k是50,p是1~2^32中任意一个数,不保证为质数。

  这道题难在思路的转化,如果你在思考怎么快速求组合数,什么O(n)预处理,O(1)求组合数,那么你已经跑偏了,显然NK这个你O(n)也跑不过。这个要求的组合数也没什么特殊的性质,不会是什么结论题。那唯一的可以发现的方向就是如何把问题转化为递推、矩阵加速递推。设f(i,j)表示ΣC(i,x)%p,x%k=j。由杨辉三角递推式,其实可以转化成f(i,j)=f(i-1,j)+f(i-1,j-1).当然你还得考虑j=0时,回归原式,你发现其实应该是f(i,j)=f(i-1,j)+f(i-1,(j-1+k)%k)。那么我们可以设置一个1*k的状态矩阵F和一个k*k的状态转移矩阵A,显然我们需要乘A的nk次幂,用快速幂就好了。最后输出F【r】就是答案。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,r,k,p,a[50][50],f[50][50],c[50][50],ans[50][50];
void mul(int b[50][50],int d[50][50]){
    memset(c,0,sizeof(c));
    for(int i=0;i<k;++i)
        for(int j=0;j<k;++j)
            for(int l=0;l<k;++l)
                c[i][j]=(c[i][j]+1LL*b[i][l]*d[l][j]%p)%p;
    for(int i=0;i<k;++i)
        for(int j=0;j<k;++j)
            b[i][j]=c[i][j];
}
int main(){
    scanf("%d%d%d%d",&n,&p,&k,&r);
    for(int i=0;i<=k-2;++i) a[i][i]=a[i][i+1]=1;
    a[k-1][k-1]++,a[k-1][0]++; //这里一定要注意,为什么使用++而不直接赋值为1,因为你要考虑k=1的情况
    f[0][0]=1;
    ll siz=1LL*n*k;
    for(int i=0;i<k;++i) ans[i][i]=1;
    for(;siz;siz>>=1){
        if(siz&1) mul(ans,a);
        mul(a,a);
    }
    mul(f,ans);
    printf("%d\n",f[0][r]);
    return 0;
}

 

speech.gif posted on 2019-01-18 09:24 kgxpbqbyt 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值