BZOJ 4870 [Shoi2017]组合数问题

题解:

解题思路,发现式子的意义。

从nk个物品中选出%k为r个物品的方案数

然后DP

 

然后用矩阵快速幂加速

注意k==0的情况!!!

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=60;
typedef long long Lint;
int mm;
int n,m,r;

struct Mat{
	Lint arr[maxn][maxn];
	Mat(){
		memset(arr,0,sizeof(arr));
	}
	void Clea(){
		memset(arr,0,sizeof(arr));
	}
	void MakeE(){
		memset(arr,0,sizeof(arr));
		for(int i=0;i<m;++i)arr[i][i]=1;
	}
}Mx,My,Mz,Ma,Mret;

void Mul(){
	Mz.Clea();
	for(int i=0;i<m;++i){
		for(int j=0;j<m;++j){
			for(int k=0;k<m;++k){
				Mz.arr[i][j]=(Mz.arr[i][j]+Mx.arr[i][k]*My.arr[k][j])%mm;
			}
		}
	}
}

void Ksm(Lint p){
	Mret.MakeE();
	for(;p;p>>=1){
		if(p&1){
			Mx=Ma;My=Mret;Mul();Mret=Mz;
		}
		Mx=Ma;My=Ma;Mul();Ma=Mz;
	}
}

int main(){
	scanf("%d%d%d%d",&n,&mm,&m,&r);
	for(int i=0;i<m;++i){
		Ma.arr[i][(i-1+m)%m]++;
		Ma.arr[i][i]++;
	}
	Ksm(1LL*n*m-1);
	printf("%lld\n",(Mret.arr[r][0]+Mret.arr[r][1%m])%mm);
	return 0;
}

 

  

 

posted @ 2018-03-13 19:13  ws_zzy  阅读(136)  评论(0编辑  收藏  举报