[BZOJ 2326][HNOI2011]数学作业

2326: [HNOI2011]数学作业

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2395  Solved: 1396
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

Sample Output

题解

这题看起来还是很一颗赛艇的...

一看数据范围大概就知道是个 $O(\log(n))$ 或者 $O(1)$ 好题了OwO

这题的滑稽之处在于这题它...emmmm...矩阵会变=.=

大概需要在每个 $[10^k,10^{k+1})$ 都用自己的矩阵跑一遍快速幂.

矩阵大概长这样:

\[\begin{bmatrix}10^{k+1} & 1 & 1\\ 1 & 1 & 0\\ 1 & 0 & 1\end{bmatrix}\]

然后注意一下边界条件以及分层的时候每层的区间左闭右开就好了...

(被左闭右开坑到死然后一直找不到错对拍随机数据还拍不出来甚至标程跑炸了都拍不出)

参考代码

GitHub

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 
 7 long long n,p;
 8 long long v[3]={0,0,1};
 9 
10 void Calc(long long,long long);
11 
12 int main(){
13     scanf("%lld%lld",&n,&p);
14     long long t=10;
15     while(n>=t){
16         Calc(t,t-t/10);
17         t*=10;
18     }
19     Calc(t,n-t/10+1);
20     printf("%lld\n",v[0]);
21     return 0;
22 }
23 
24 void Calc(long long k,long long t){
25     long long vt[3],mt[3][3];
26     long long m[3][3]={{k%p,0,0},{1,1,0},{1,1,1}};
27     while(t>0){
28         if((t&1)!=0){
29             memset(vt,0,sizeof(vt));
30             for(int i=0;i<3;++i){
31                 for(int j=0;j<3;++j){
32                     (vt[j]+=v[i]*m[i][j])%=p;
33                 }
34             }
35             memcpy(v,vt,sizeof(vt));
36         }
37         memset(mt,0,sizeof(mt));
38         for(int i=0;i<3;++i){
39             for(int j=0;j<3;++j){
40                 for(int k=0;k<3;++k){
41                     (mt[i][j]+=m[i][k]*m[k][j])%=p;
42                 }
43             }
44         }
45         memcpy(m,mt,sizeof(mt));
46         t>>=1;
47     }
48 }
Backup

 

posted @ 2017-11-07 10:27  rvalue  阅读(304)  评论(0编辑  收藏  举报