4870: [Shoi2017]组合数问题
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 295 Solved: 158
[Submit][Status][Discuss]
Description
Input
第一行有四个整数 n, p, k, r,所有整数含义见问题描述。
1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1
Output
一行一个整数代表答案。
Sample Input
2 10007 2 0
Sample Output
8
HINT
Source
黑吉辽沪冀晋六省联考
定义 f(i,j)=∑∞t=0Cj+tki
打个表不难发现, f(i,j)=f(i−1,j)+f(i−1,(j−1) mod k)
于是大力矩乘就可以了
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 51;
typedef long long LL;
int n,K,p,r;
inline int Mul(const LL &x,const LL &y) {return x * y % p;}
inline int Add(const int &x,const int &y) {return x + y < p ? x + y : x + y - p;}
struct data{
int a[N][N]; data(){memset(a,0,sizeof(a));}
data operator * (const data &b)
{
data c;
for (int k = 0; k < K; k++)
for (int i = 0; i < K; i++)
for (int j = 0; j < K; j++)
c.a[i][j] = Add(c.a[i][j],Mul(a[i][k],b.a[k][j]));
return c;
}
}G;
data ksm(LL y)
{
data ret; for (int i = 0; i < K; i++) ret.a[i][i] = 1;
for (; y; y >>= 1LL)
{
if (y & 1LL) ret = ret * G;
G = G * G;
}
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> p >> K >> r;
for (int i = 0; i < K; i++)
++G.a[(i - 1 + K) % K][i],++G.a[i][i];
data T = ksm(1LL * n * K);
cout << T.a[0][r] << endl;
return 0;
}