随笔- 22  文章- 0  评论- 10  阅读- 1579 

[HNOI2011]数学作业

题目描述

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

给定正整数 n,m,要求计算 Concatenate(n)mod m 的值,其中 Concatenate(n) 是将 1n 所有正整数 顺序连接起来得到的数。

例如,n=13 , Concatenate(n)=12345678910111213。小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

输入格式

一行两个正整数 n,m

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

13 13

样例输出 #1

4

提示

【数据范围】
对于 30% 的数据,1n106
对于 100% 的数据,1n10181m109

思路

观察这个Concatenate数,不难得到递推式:

Concatenate[i]=Concatenate[i1]×10len(i)+i

其中len(i)i的位数。

100%数据是1n1018,暴力推肯定不行,考虑矩阵加速。

设状态矩阵为[F[i]i1],它应该从[F[i1]i11]转移过来。因此可得转移矩阵为[10len(i)00110111]。每次i的位数增加的时候更新len(i)的值即可。

代码

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;
int n,mod,num,r,k,kk;
struct matrix
{
    int mat[4][4],n,m;
    matrix(int a,int b)
    {
        n=a,m=b;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                mat[i][j]=0;
    }
    void set_i()
    {
        for(int i=1;i<=n;i++)
                mat[i][i]=1;
    }
    matrix operator *(matrix b)
    {
        matrix ans(n,b.m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=b.m;j++)
                for(int k=1;k<=m;k++)
                    ans.mat[i][j]=(ans.mat[i][j]+(mat[i][k]*b.mat[k][j])%mod)%mod;
        return ans;
    }
};
matrix qpow(matrix a,int b)
{
    matrix ans(a.n,a.m);
    ans.set_i();
    while(b)
    {
        if(b&1)ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
int numb(int x)
{
    int ret=0;
    while(x)
    {
        x/=10;
        ret++;
    }
    return ret;
}
signed main()
{
    scanf("%lld%lld",&n,&mod);
    num=numb(n);
    matrix f(1,3);
    f.mat[1][1]=f.mat[1][2]=f.mat[1][3]=1;
    matrix bb(3,3);
    bb.mat[1][1]=10;bb.mat[2][1]=bb.mat[2][2]=bb.mat[3][1]=bb.mat[3][2]=bb.mat[3][3]=1;
    matrix pro(3,3);
    pro.set_i();

    int mi=9,now=0;
    for(int i=1;i<num;i++)
    {
        now+=mi;
        if(i==1)pro=pro*qpow(bb,mi-1);
        else pro=pro*qpow(bb,mi);
        bb.mat[1][1]=(bb.mat[1][1]*10)%mod;
        mi=(mi<<1)+(mi<<3);
    }
    if(num==1)pro=pro*qpow(bb,n-now-1);
    else pro=pro*qpow(bb,n-now);
    f=f*pro;
    printf("%lld",f.mat[1][1]%mod);
    return 0;
}

 posted on   hu_led  阅读(162)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示