[BZOJ 2326] 數學作業

Description

1 ~n 的所有自然數連接在一起構成一個新數,求這個數模m 的值,其中n1018,m109

題目傳送門


Tag

矩陣乘法


Solution

構造關於n 的遞推數列,然後按照n 的位數分段矩陣快速冪即可。
思路非常顯然不過這裏有一個細節需要注意
我們找出的遞推式是

10t00110011ann+11=an+1n+21

其中tn+1 的位數。
爲了保證乘的前後始終是一個列矩陣,我們要把矩陣乘在左邊,這樣的話做乘法的時候就要從左邊乘而不是從右邊乘


AC Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

struct matrix
{
    LL a[3][3];
    matrix(){memset(a,0,sizeof(a));}
    void init()
    {
        memset(a,0,sizeof(a));
        for(int i=0;i<3;i++)a[i][i]=1;
    }
}g,ans,mrs;
int mod;
LL n,tmp[3];
char c;

template<typename T>
inline void read(T& x)
{
    x=0,c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c))x=x*10+c-'0',c=getchar();
}
matrix operator * (matrix a,matrix b)
{
    for(int i=0;i<3;i++)for(int j=0;j<3;j++)
    {
        mrs.a[i][j]=0;
        for(int k=0;k<3;k++)mrs.a[i][j]+=a.a[i][k]*b.a[k][j];
        mrs.a[i][j]%=mod;
    }
    return mrs;
}
inline void Pow(matrix A,LL b)
{
    while(b)
    {
        if(b&1)ans=A*ans;//如果寫成ans=ans*A的話就會WA
        A=A*A,b>>=1;
    }
}

int main()
{
    read(n),read(mod),n++;
    ans.init();
    g.a[0][1]=g.a[1][1]=g.a[1][2]=g.a[2][2]=1;
    for(LL now=10,pre=1;;pre=now,now*=10)
    {
        g.a[0][0]=now%mod;
        Pow(g,min(now,n)-pre);
        if(now>=n)break;
    }
    printf("%lld",(ans.a[0][1]+ans.a[0][2])%mod);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章