【HNOI2011】数学作业 题解(递推+矩阵快速幂)

题目链接

题目大意:求$1-n$所拼接起来的数$mod m$的值。

-----------------------------------

递推式子很好想:$f_i=f_{i-1}*10^{lg i+1}+i$

看到数据范围,肯定不能$O(n)$递推。考虑矩阵加速。

转移矩阵为:

$egin{pmatrix}10^k&0&0\1&1&0\1&1&1end{pmatrix}$

因为$10^k$是不确定的,所以我们要根据范围来分情况作乘法。详见代码。

PS:这个题我调了好久……要注意幂的大小和矩阵初始化。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,mod,cnt;
struct node
{
    int a[4][4];
    node(){
        memset(a,0,sizeof(a));
    }
    inline void build(){
        for (int i=1;i<=3;i++) a[i][i]=1;
    }
}ans;
node operator *(const node x,const node y)
{
    node z;
    for (int k=1;k<=3;k++)
        for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
                z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    return z;
}
inline int qcal(int x,int y)
{
    int res=1;     
    while(y){
        if (y&1) res=res*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return res%mod;
}
signed main()
{
    cin>>n>>mod;
    ans.build();
    for (int i=1;;i*=10)
    {
        cnt++;int mi;
        node a;a.a[1][1]=qcal(10,cnt);
        a.a[2][1]=a.a[2][2]=a.a[3][1]=a.a[3][2]=a.a[3][3]=1;
        if (n<i*10)
        {
            mi=n-i+1;
            while(mi)
            {
                if (mi&1) ans=ans*a;
                a=a*a;
                mi>>=1;
            }
            int sum=ans.a[3][1];
            printf("%lld",sum%mod);
            return 0;
        }
        mi=i*9;
        while(mi)
        {
            if (mi&1) ans=ans*a;
            a=a*a;
            mi>>=1;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13346667.html