【HNOI 2011】BZOJ 2326-数学作业

按照教练的要求来写一写历年HNOI的题目...挑几道好写的来做

题意我就不说了。

一开始就被BZOJ上的Tag剧透了个爽,直接省掉70%的思考过程...

    很容易可以得出的O(n)递推式 :f[n] = f[n-1] * 10 len(n) + n

然后我们考虑如何用矩阵乘法来简化这个式子。

因为len(n)是一个变量,而且表示比较复杂。因此只需要将n分成几段,比如1-9,10-99这些位数相同的区间。

观察一下式子,里面有f[n],f[n-1],n这些变量,10a这个常量。

假设现在有这么一个矩阵,在已知f[n-1],n的情况下能够得出f[n],n+1就好了是吧?

    f[n-1]  ——>  f[n-1] * 10a + n

    n ——> n+1

————————————————————————————————————————

    f[n-1]           |                      |                          f[n-1] * 10a

    n             *   |                      |              =          n+1

    1                 |                       |                         1

易之,所求的矩阵应该是

10a     1         0

0         1         1

0         0         1

那么把这个矩阵快速幂一下,然后改一下[1][1]的值继续快速幂,最后与

0

1

1

乘以下,[1][1]位的就是答案了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6
 7 typedef long long ll;
 8 int i,j,n,m,k;
 9 ll N,p,a;
10
11 struct matrix
12 {
13     int n,m; ll d[4][4];
14     void clear() { n = m = 0; memset(d,0,sizeof(d)); }
15 } S,T;
16
17 matrix operator * (const matrix &a,const matrix &b)
18 {
19     matrix ans;
20     ans.clear();
21     for (int i = 1; i <= a.n; i++)
22         for (int j = 1; j <= b.m; j++)
23             for (int k = 1; k <= a.m; k++)
24                 ans.d[i][j] += a.d[i][k] * b.d[k][j],ans.d[i][j] %= p;
25     ans.n = a.n; ans.m = b.m;
26     return ans;
27 }
28
29 matrix Power(matrix a,ll b)
30 {
31     matrix ans; ans.clear(); ans.n = ans.m = 3;
32     ans.d[1][1] = ans.d[2][2] = ans.d[3][3] = 1;
33     while (b)
34     {
35         if (b & 1) ans = ans * a;
36         a = a * a;
37         b >>= 1;
38     }
39     return ans;
40 }
41
42 int main()
43 {
44     scanf("%lld %lld\n",&N,&p);
45
46     S.n = S.m = 3; T.n = 3; T.m = 1;
47     S.d[1][2] = S.d[2][2] = S.d[2][3] = S.d[3][3] = T.d[2][1] = T.d[3][1] = 1;
48
49     a = 1;
50     while (1)
51     {
52         a = a * 10;
53
54         S.d[1][1] = a % p;
55
56         ll k = min(a-a/10,N-a/10+1);
57         T = Power(S,k) * T;
58         if (a > N) break;
59     }
60
61     printf("%lld\n",T.d[1][1]);
62
63     return 0;
64 }

BZOJ 2326

时间: 2024-10-09 20:52:11

【HNOI 2011】BZOJ 2326-数学作业的相关文章

BZOJ 2326 数学作业

矩阵快速幂. #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; struct matrix { long long a[4][4]; long long n,m; }a,b; long long n,m,l=1,r=10; long long mmul(long long a,

矩阵乘法专题4——bzoj 2326 [HNOI2011] 数学作业 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24963747 [原题] 2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 853  Solved: 473 [Submit][Status] Description [分析]我们按数字的位数来划分.对于K位数,我们就可以专门设计一个矩阵来计算. 然后就是注意细节了. [代码] #include

【BZOJ 2326】 [HNOI2011]数学作业

2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1100  Solved: 625 [Submit][Status] Description 矩阵乘法. 可以用类似于秦九韶算法,把被取模的数拆开. 如123%m=(((1%m)*10+2)%m*10+3)%m 我们发现对于位数相同的数的计算方法是一样的,想到矩阵乘法. 对于1位的数: matrix x=10^1  0  0 1       1  0 0  

[BZOJ 2326] [HNOI2011] 数学作业 【矩阵乘法】

题目链接:BZOJ - 2326 题目分析 数据范围达到了 10^18 ,显然需要矩阵乘法了! 可以发现,向数字尾部添加一个数字 x 的过程就是 Num = Num * 10^k + x .其中 k 是 x 的位数. 那么位数相同的数字用矩阵乘法处理就可以了. [Num, x, 1] * [10^k, 0, 0] = [Num*10^k+x, x+1, 1] [      1, 0, 0] [      0, 1, 1] 枚举位数,做多次矩阵乘法. 其中两个整数相乘可能会爆 LL ,那么就用类似

2326: [HNOI2011]数学作业

2326: [HNOI2011]数学作业 Description 不说什么ACTY了.. 题解: 线性的递推很容易写出来,f[i]=f[i-1]*10+i  (mod) 但是n很大,就需要用到矩阵乘法了.. 我们够造矩阵 10^i   0       0       f[i-1]        f[i] 1        1       0   *   i-1     =    i 1        1       1        1             1 #include<stdio.

codevs 2314 数学作业

2314 数学作业 2011年省队选拔赛湖南 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M ,要求计算 Concatenate (1 .. N ) Mod M 的值,其中Concatenate (1 .. N ) 是将所有正整数 1, 2, …, N 顺序连接起来得到的数.例如, N = 13, Concatenate (1 ..

bzoj2326【HNOI2011】数学作业

2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1648  Solved: 972 [Submit][Status][Discuss] Description (f[n])(10^k  1    1)(f[n-1]) ( n )=(0      1    1)( n-1 ) ( 1 ) (0      0    1)(  1  ) 然后分段矩阵乘法.这道题调了整整一晚上,忘记每一步运算都取模,这道题很容易

【bzoj2326】【HNOI2011】【数学作业】

2326: [HNOI2011]数学作业 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1264 Solved: 727 [Submit][Status][Discuss] Description 思路:其实很容易可以想到,当我们所要连接的数的位数不同的时候,我们需要把原来的数增大的倍数是不一样的. 所以我们需要分阶段来做矩乘. 根据数的位数分为1->9;10->99---10^k->10^(k+1)-1;就可以了. 但是我们还需要注意一

【BZOJ2326】[HNOI2011]数学作业 矩阵乘法

[BZOJ2326][HNOI2011]数学作业 题解:对于位数相同的数字,这显然是满足矩乘性质的. 那么我们枚举每一位,如果当前i=10^k,那么维护行向量(sum,now,1),now代表当前的数,每次将sum*=i再加上now,now+=1即可. #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; ll n,P; st