[HNOI2011]数学作业

题目描述

小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:

给定正整数 N 和 M,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 ..N)是将所有正整数 1, 2, …, N 顺序连接起来得到的数。例如,N = 13, Concatenate (1 .. N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

输入输出格式

输入格式:

从文件input.txt中读入数据,输入文件只有一行且为用空格隔开的两个正整数N和M,其中30%的数据满足1≤N≤1000000;100%的数据满足1≤N≤1018且1≤M≤109.

输出格式:

输出文件 output.txt 仅包含一个非负整数,表示 Concatenate (1 .. N) Mod M 的值。

输入输出样例

 输入样例#1:

13 13

 输出样例#1:

4
题解:

这道题如果不是要考虑每一次乘上的数是10的几次方的话,那便是裸的矩阵快速幂,但是加上的话也无非就是多分几种情况讨论罢了。

首先看递推式:f[i]=f[i-1]*10^k+i(可以看出只要对k讨论)

然后写出两个矩阵:{{0,1,1},{0,0,0},{0,0,0}}和{{k%m,0,0},{1,1,0},{0,1,1}};

快速幂即可。

代码如下:(注意每次循环的分类讨论)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
using namespace std;
typedef long long lol;
lol n,m,now,pre;
struct matrix
{
    lol a[3][3];
    matrix(){for(int i=0;i<3;i++)for(int j=0;j<3;j++)a[i][j]=0;}
    matrix(lol b[3][3]){for(int i=0;i<3;i++)for(int j=0;j<3;j++)a[i][j]=b[i][j];}
    friend matrix operator * (const matrix a,const matrix b)
    {
        matrix ans;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                for(int k=0;k<3;k++)
                ans.a[i][j]=(ans.a[i][j]+(a.a[i][k]%m)*(b.a[k][j]%m)%m)%m;
        return ans;
    }
}S,T;
lol gi()
{
    lol ans=0,f=1;
    char i=getchar();
    while(i<‘0‘||i>‘9‘){if(i==‘-‘)f=-1;i=getchar();}
    while(i>=‘0‘&&i<=‘9‘){ans=ans*10+i-‘0‘;i=getchar();}
    return ans*f;
}
int main()
{
    lol i,j,k;
    n=gi();m=gi();
    lol s[3][3]={{0,1,1},{0,0,0},{0,0,0}};
    S=matrix(s);
    for(k=10;now<n;k*=10)
    {
        lol t[3][3]={{k%m,0,0},{1,1,0},{0,1,1}};
        T=matrix(t);
        pre=min(k-1,n)-now;
        while(pre)
        {
            if(pre&1)S=S*T;
            T=T*T;
            pre>>=1;
        }
        now=min(k-1,n);
    }
    printf("%lld\n",S.a[0][0]);
    return 0;
}
时间: 2024-08-05 11:14:00

[HNOI2011]数学作业的相关文章

矩阵乘法专题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

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.

【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

洛谷P3216 [HNOI2011]数学作业

洛谷P3216 [HNOI2011]数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 ..N)是将所有正整数 1, 2, -, N 顺序连接起来得到的数.例如,N = 13, Concatenate (1 .. N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,

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}

bzoj2326 [HNOI2011]数学作业

分析:设f[i]为1~i组成的数,可以得到f[i] = f[i-1] * 10^k + i.对于一个序列求第n项,一般可以用矩阵乘法来加速,但是每一个矩阵只能对应一个不变的递推式,这个式子中的k会变,那怎么办呢?那么在1~9,10~99,100~999每一次构造一个矩阵就好了,具体的矩阵如下: f(i + 1)       f(i)  10^k,1,1 i        =     i - 1    *    0, 1, 1 1   1 0, 0, 1 #include <cstdio> #i

bzoj2326:[HNOI2011]数学作业(分段矩阵乘法)

题目大意:输入n(n<=10^18)和m,将1~n的整数连起来模m输出,比如n=13则输出12345678910111213模m的数. 设f[i]为1~i整数连起来模m的数,i的位数为k,则有f[i]=(f[i-1]*10^k+i)mod m.可以发现f[i-1]和10^k都是会变化的,不能直接矩乘,这就尴尬了>_<.但是仔细想想(跑去问CZL),其实可以分段来矩乘,把k一样的数矩乘(1..9一样,10..99一样,100..999一样)就行了. orz CZL初二的时候1A,然而我却W

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