BZOJ 2326 HNOI 2011 数学作业 矩阵乘法

题目大意

求一个这样的数:“12345678910111213……”对m取模的值。

思路

观察这个数字的特点,每次向后面添加一个数。也就是原来的数乘10^k之后在加上一个数。而且处理每个数量级的时候是相似的。所以就可以用矩阵乘法来加速。我构造的矩阵是这样的。

[当前数字累加数字1]×???数量级10011001???=[新的数字累加数字+11]

CODE

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MO p
using namespace std;

long long k,p;

struct Matrix{
    long long num[5][5];
    int w,h;

    Matrix(int _,int __):w(_),h(__) {
        memset(num,0,sizeof(num));
    }
    Matrix() {
        memset(num,0,sizeof(num));
    }
    Matrix operator *(const Matrix &a)const {
        Matrix re(w,a.h);
        for(int i = 1; i <= w; ++i)
            for(int j = 1; j <= a.h; ++j)
                for(int k = 1; k <= h; ++k)
                    re.num[i][j] = (re.num[i][j] + num[i][k] * a.num[k][j] % MO) % MO;
        return re;
    }
};

inline Matrix QuickPower(Matrix a,long long k)
{
    Matrix re(3,3);
    re.num[1][1] = re.num[2][2] = re.num[3][3] = 1;
    while(k) {
        if(k&1) re = re * a;
        a = a * a;
        k >>= 1;
    }
    return re;
}

int main()
{
    cin >> k >> p;
    long long now = 10,ans_num = 0;
    while(k >= now - now / 10 && now < 1e18) {
        k -= now - now / 10;
        Matrix right(3,3);
        right.num[1][1] = now % MO;
        right.num[2][1] = right.num[2][2] = right.num[3][2] = right.num[3][3] = 1;
        right = QuickPower(right,now - now / 10);
        Matrix left(1,3);
        left.num[1][1] = ans_num;
        left.num[1][2] = (now / 10) % MO;
        left.num[1][3] = 1;
        ans_num = (left * right).num[1][1];
        now *= 10;
    }
    Matrix right(3,3);
    right.num[1][1] = now % MO;
    right.num[2][1] = right.num[2][2] = right.num[3][2] = right.num[3][3] = 1;
    right = QuickPower(right,k);
    Matrix left(1,3);
    left.num[1][1] = ans_num;
    left.num[1][2] = (now / 10) % MO;
    left.num[1][3] = 1;
    cout << (left * right).num[1][1] << endl;
    return 0;
}
时间: 2024-10-15 09:01:10

BZOJ 2326 HNOI 2011 数学作业 矩阵乘法的相关文章

[BZOJ 2326][HNOI 2011]数学作业(矩阵快速幂)

蒟蒻线性代数太烂了...这个逼题居然卡了半天才做出来,弱的不行啊... 矩阵快速幂,把n这个len位数拆成len次分段快速幂就可以了. 注意取模的数字m<=1e9,所以矩阵乘法运算时要先对乘数取模,防止中间运算结果太大溢出,坑爹啊 代码: #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #d

【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  

【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

BZOJ 2326 HNOI2011 数学作业 矩阵乘法

题目大意:求1234567891011121314...n mod m 的值 设F(n)=1234567891011121314...n 那么显然有F(n)=F(n-1)*(floor(lgn)+1)+n 于是我们可以矩乘 将数字按照floor(lgn)+1分类 构造状态矩阵F(n) n+1 1 初值为0 1 1 1~9的转移矩阵为 10 0 0 1 1 0 0 1 1 10~99的转移矩阵为 100 0 0 1 1 0 0 1 1 以此类推 注意构造矩阵的时候要取模不然会挂 #include

BZOJ2326 HNOI2011 数学作业 矩阵乘法

题意:求12345……101112……(N-1)N mod M的值(被模数就是1-N顺次连接起来). 题解:丧病的数学老师,看自己写的题解都看不懂了QAQ,首先设${f_i}$=前i个数连接起来 mod M的值,然后按位数不断转移,也就是说,假定当前要增加的数i最高位是10^k,那么\[{f_i} = ({10^{k + 1}}{f_{i - 1}} + i)\bmod M\] 所以\[\left( {\begin{array}{*{20}{c}}{{f_{{{10}^{k + 1}} - 1}

BZOJ 4870 [Shoi2017]组合数问题 ——动态规划 矩阵乘法

注意到$r<k$ 别问我为什么要强调. 考场上前30分水水. 然后写阶乘的时候大力$n\log {n}$预处理 本机跑的挺快的,然后稳稳的T掉了. 然后就是简单的矩阵乘法了. #include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm

bzoj 1875: [SDOI2009]HH去散步 -- 矩阵乘法

1875: [SDOI2009]HH去散步 Time Limit: 20 Sec  Memory Limit: 64 MB Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢变化的人,所以他每 天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法. 现在给你学校的地图(假设每条路的长度都 是一样的都是1),问长度为t,从给定

数学(矩阵乘法):HDU 4565 So Easy!

So Easy! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3804    Accepted Submission(s): 1251 Problem Description A sequence Sn is defined as: Where a, b, n, m are positive integers.┌x┐is the ce

bzoj 3231: [Sdoi2008]递归数列【矩阵乘法】

今天真是莫名石乐志 一眼矩阵乘法,但是这个矩阵的建立还是挺有意思的,就是把sum再开一列,建成大概这样 然后记!得!开!long!long!! #include<iostream> #include<cstdio> using namespace std; const int N=20; long long n,b[N],c[N],sum,l,r,mod; struct jz { long long a[N][N]; jz operator * (const jz &b)