首页 > 代码库 > [HNOI2011]数学作业

[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;
}

 

 

[HNOI2011]数学作业