題意:
題目梗概給出函數式和限制條件
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .
輸入k(k<2*10^9)和m(m<10^5),輸出f(k)%m的結果
思路:
很明顯的矩陣乘法
a0 | a1 | a2 | a3 | a4 | a5 | a6 | a7 | a8 | a9 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
*
f(x-1) |
f(x-2) |
f(x-3) |
f(x-4) |
f(x-5) |
f(x-6) |
f(x-7) |
f(x-8) |
f(x-9) |
f(x-10) |
=
f(x) |
f(x-1) |
f(x-2) |
f(x-3) |
f(x-4) |
f(x-5) |
f(x-6) |
f(x-7) |
f(x-8) |
f(x-9) |
所以我們只需求上面(10x10)矩陣的(n-9)次冪,再乘以(10x1)(f(9)~f(0))的矩陣即可
(10x1) =
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
代碼:
/**************************************************************
Problem: HDU_1757
User: soundwave
Language: C++
Result: Accepted
Time: 0ms
Memory: 1584KB
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
typedef vector<int> Vint;
typedef vector<Vint> VVint;
typedef __int64 LL;
int MOD;
//矩陣乘法
VVint calc(VVint &A, VVint &B){
VVint C(A.size(), Vint(A.size()));
for(int i=0; i<A.size(); i++)
for(int j=0; j<B[0].size(); j++)
for(int k=0; k<B.size(); k++)
C[i][j] = (C[i][j] + (A[i][k]*B[k][j])%MOD) % MOD;
return C;
}
//二分快速冪
VVint my_pow(VVint A, LL c){
VVint B(A.size(),Vint(A.size()));
for(int i=0; i<A.size(); i++)
B[i][i] = 1;
if(c == 1) return A;
while(c>0){
if(c&1) B = calc(B,A);
A = calc(A,A);
c>>=1;
}
return B;
}
int main(){
LL k;
while(~scanf("%I64d%d", &k, &MOD)){
VVint A(10,Vint(10));
Vint B(10);
for(int i=0; i<10; i++)
scanf("%d", &B[i]);
if(k < 10) {printf("%I64d\n", k); continue;}
for(int i=0; i<10; i++)
A[0][i] = B[i];
for(int i=1; i<10; i++)
A[i][i-1] = 1;
A = my_pow(A,k-9);
k = 0;
for(int i=0; i<9; i++)
k = (k + (A[0][i]*(9-i))%MOD) % MOD;
printf("%I64d\n", k);
}
return 0;
}
/*
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
-------------------
45
104
*/
反思:
最重要的是求出遞推關係來,然後轉化爲矩陣