bzoj2326 [HNOI2011]数学作业

某次noip模拟赛遇见了,打完后发现它,二话不说就A了。

题目

其实就是简单的矩阵快速幂,构造矩阵
{10^a,0,0}
{1, 1,0}
{0, 1,1}
在乘一乘,处理细节,就好了。

#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
using namespace std;
long long n,tmp,k,mod;
long long f[20];
struct matrix{
    int h;
    int l;
    long long data[5][5];
};
matrix a,b,c;
matrix multiply(matrix A,matrix B)
{
    matrix ans;
    ans.h=A.h,ans.l=B.l;
    for(int i=1;i<=ans.h;i++)
        for(int j=1;j<=ans.l;j++)
            ans.data[i][j]=0;
    for(int i=1;i<=ans.h;i++)
        for(int j=1;j<=ans.l;j++)
            for(int k=1;k<=A.l;k++)
                ans.data[i][j]=(ans.data[i][j]+A.data[i][k]*B.data[k][j])%mod;
    return ans;
}
void write(matrix A)
{
    for(int i=1;i<=A.h;i++)
    {
        for(int j=1;j<=A.l;j++)
            cout<<A.data[i][j]<<" ";
        cout<<endl;
    }
}
matrix ksm(matrix A,long long B)
{
    matrix ans;
    ans.h=A.h,ans.l=A.l;
    for(int i=1;i<=ans.h;i++)
        for(int j=1;j<=ans.l;j++)
            ans.data[i][j]=(i==j);
    while(B)
    {
        if(B&1)ans=multiply(ans,A);
        B>>=1;
        A=multiply(A,A);
    }
    return ans;
}
int main()
{
    //freopen("math.in","r",stdin);
    //freopen("math.out","w",stdout);
    cin>>n>>mod;
    if(n<=100000)
    {
        for(int i=1;i<=min((long long)9,n);i++)
            tmp=(tmp*10+i)%mod;
        for(int i=10;i<=min((long long)99,n);i++)
            tmp=(tmp*100+i)%mod;
        for(int i=100;i<=min((long long)999,n);i++)
            tmp=(tmp*1000+i)%mod;
        for(int i=1000;i<=min((long long)9999,n);i++)
            tmp=(tmp*10000+i)%mod;
        for(int i=10000;i<=min((long long)99999,n);i++)
            tmp=(tmp*100000+i)%mod;
        for(int i=100000;i<=min((long long)999999,n);i++)
            tmp=(tmp*1000000+i)%mod;
        cout<<tmp%mod;
        return 0;
    }
    f[0]=1;
    for(int i=1;i<=18;i++)f[i]=f[i-1]*10;
    a.h=1,a.l=3,a.data[1][1]=0;a.data[1][2]=1;a.data[1][3]=1;
    b.h=3,b.l=3,b.data[1][1]=1;b.data[1][2]=0;b.data[1][3]=0;
    b.data[2][1]=1;b.data[2][2]=1;b.data[2][3]=0;
    b.data[3][1]=0;b.data[3][2]=1;b.data[3][3]=1;
    for(int i=1;n>0;i++)
    {
        b.data[1][1]=f[i]%mod;
        if(f[i]==0)k=n;
        else k=min(n,f[i]-f[i-1]);
        c=ksm(b,k);
        a=multiply(a,c);
        n-=k;
    }
    cout<<a.data[1][1];
    return 0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值