1. 程式人生 > >【BZOJ4870】組合數問題 [矩陣乘法][DP]

【BZOJ4870】組合數問題 [矩陣乘法][DP]

mes def online cli char spa ++ soft sed

組合數問題

Time Limit: 10 Sec Memory Limit: 512 MB
[Submit][Status][Discuss]

Description

  技術分享

Input

  第一行有四個整數 n, p, k, r,所有整數含義見問題描述。

Output

  一行一個整數代表答案。

Sample Input

  2 10007 2 0

Sample Output

  8

HINT

  1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1

Solution

  首先,不難發現,題目的本質是:從n*k個中選模k等於r個的方案數,那麽輕易地寫出了暴力DPf[i][j]=f[i-1][j]+f[i-1][(j-1+k)%k]

  然後套個矩陣乘法優化一下即可。

Code

技術分享
#include<iostream>  
#include<string>  
#include<algorithm>  
#include<cstdio>  
#include<cstring>  
#include<cstdlib>  
#include<cmath>
using
namespace std; typedef long long s64; const int ONE = 55; int n,MOD,num,r; inline s64 get() { s64 res=1,Q=1; char c; while( (c=getchar())<48 || c>57) if(c==-)Q=-1; if(Q) res=c-48; while((c=getchar())>=48 && c<=57) res
=res*10+c-48; return res*Q; } struct Matrix { s64 v[ONE][ONE]; friend Matrix operator *(Matrix a,Matrix b) { Matrix record; for(int i=0;i<num;i++) for(int j=0;j<num;j++) { record.v[i][j]=0; for(int k=0;k<num;k++) record.v[i][j] = (s64)(record.v[i][j] + a.v[i][k]*b.v[k][j] % MOD) % MOD; } return record; } }; Matrix B,Ans; Matrix Quickpow(Matrix a,s64 b) { Matrix res; for(int i=0;i<num;i++) res.v[i][i] = 1; while(b) { if(b&1) res = res*a; a = a*a; b>>=1; } return res; } int main() { n=get(); MOD=get(); num=get(); r=get(); for(int i=0;i<num;i++) { B.v[i][i]++; B.v[((i-1)%num+num)%num][i]++; } Ans = Quickpow(B, (s64)n*num); cout<<Ans.v[0][r]; }
View Code

【BZOJ4870】組合數問題 [矩陣乘法][DP]