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 .. N ) = 12345678910111213. 小 C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望 你能编写一个程序帮他解决这个问题。

输入描述 Input Description

只有一行 为用空格隔开的两个正整数 N 和 M

输出描述 Output Description

仅包含一个非负整数,表示 Concatenate (1 .. N ) Mod M 的值

样例输入 Sample Input

13 13

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

其中 30%的数据满足1≤ N ≤1000000;100%的数据满足1≤ N ≤1018且1≤ M ≤109

/*
矩阵乘法
f[i]=f[i-1]*10的i的长度次方+i
i的长度是不同的 没法直接矩阵乘法
按i的长度分情况用矩阵乘法 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
LL n,p;
LL a[5][5],b[5][5],c[5][5],f[5][5]; 
LL init()
{
    LL x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
LL slow_mul(LL a,LL b)
{
    LL ret=0;
    while(b)
    {
        if(b&1)ret+=a,ret%=p,b--;
        a<<=1;a%=p;b>>=1;
    }
    return ret;
}
LL mul(LL a[5][5],LL b[5][5])
{
    for(LL i=1;i<=3;i++)
    {
        for(LL j=1;j<=3;j++)
        {
            LL x=0;
            for(LL k=1;k<=3;k++)
            x=(x+slow_mul(a[i][k],b[k][j]))%p;
            c[i][j]=x;
        }
    }
    for(LL i=1;i<=3;i++)
    {
        for(LL j=1;j<=3;j++)
        a[i][j]=c[i][j];
    }
}
void pow(LL x)
{
    if(x==1)
    {
        memcpy(a,b,sizeof(b));
        return;
    }
    pow(x/2);
    mul(a,a);
    if(x&1)mul(a,b);
}
int main()
{
    LL i,j,k; 
    n=init();p=init();
    f[1][2]=1;f[1][3]=1;
    b[2][1]=1;b[2][2]=1;
    b[3][2]=1;b[3][3]=1;
    for(i=10;i<=n;i*=10)
    {
        b[1][1]=i%p;
        pow(i-i/10);
        mul(f,a);
    }
    b[1][1]=i%p;
    pow(n-i/10+1);
    mul(f,a);
    cout<<f[1][1]<<endl;
    return 0;
}

 

posted @ 2016-10-28 10:52  岂是蓬蒿人  阅读(133)  评论(0编辑  收藏  举报