BZOJ2326: [HNOI2011]数学作业

【传送门:BZOJ2326


简要题意:

  给出n和m,要求计算Concatenate(1...n)%m的值,其中Concatenate(1...n)是将所有正整数1,2,…,n顺序连接起来得到的数

  例如,n=13,Concatenate(1...N)=12345678910111213


题解:

  矩阵乘法

  因为肯定不能暴力算,太大了

  所以我们用矩阵记录当前的%了之后的值和当前到达哪一个正整数了

  然后一位一位地处理,因为数的位数影响答案

  如果n包含了两位数的所有数,那么10到99就每加一个之前都要乘上100

  很好的矩阵题,注意long long的处理


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL bin[21];
struct node
{
    LL a[4][4];
    node()
    {
        memset(a,0,sizeof(a));
    }
}sum,cmd;
LL m;
node chengfa(node a,node b)
{
    node c;
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            for(int k=1;k<=3;k++)
            {
                c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
            }
        }
    }
    return c;
}
node p_mod(node a,LL b)
{
    node ans;
    ans.a[1][1]=1;ans.a[2][2]=1;ans.a[3][3]=1;
    while(b!=0LL)
    {
        if(b%2LL==1LL) ans=chengfa(ans,a);
        a=chengfa(a,a);
        b/=2LL;
    }
    return ans;
}
int main()
{
    LL n;
    scanf("%lld%lld",&n,&m);
    bin[0]=1LL;for(int i=1;i<=19;i++) bin[i]=bin[i-1]*10LL;
    int len=0;LL t=n;
    while(t!=0)
    {
        t/=10;len++;
    }
    sum.a[1][1]=0LL;sum.a[1][2]=0LL;sum.a[1][3]=1LL;
    for(int i=1;i<len;i++)
    {
        cmd.a[1][1]=bin[i]%m;
        cmd.a[2][1]=1LL;cmd.a[2][2]=1LL;
        cmd.a[3][1]=1LL;cmd.a[3][2]=1LL;cmd.a[3][3]=1LL;
        LL t;
        if(i==1) t=9LL;
        else t=bin[i]-bin[i-1];
        sum=chengfa(sum,p_mod(cmd,t));
    }
    cmd.a[1][1]=bin[len]%m;
    cmd.a[2][1]=1LL;cmd.a[2][2]=1LL;
    cmd.a[3][1]=1LL;cmd.a[3][2]=1LL;cmd.a[3][3]=1LL;
    sum=chengfa(sum,p_mod(cmd,n-bin[len-1]+1));
    printf("%lld\n",sum.a[1][1]);
    return 0;
}

 

posted @ 2018-04-03 12:59  Star_Feel  阅读(157)  评论(0编辑  收藏  举报