【BZOJ2326】数学作业

数学作业


  • Description

小C数学成绩优异,于是老师给小C留了一道非常难的数学作业题: 给定正整数 N和M,要求计算Concatenate(1..N)Mod M的值,其中Concatenate(1..N)是将所有正整数1,2,…,N顺序连接起来得到的数。例如,N=13, Concatenate(1..N)=12345678910111213.小C想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

  • Input Format

只有一行,为用空格隔开的两个正整数N和M。

  • Output Format

仅包含一个非负整数,表示Concatenate(1..N)Mod M的值。

  • Sample Input

【输入样例1】
13 13
【输入样例2】
12345678910 1000000000

  • Sample Output

【输出样例1】
4
【输出样例2】
345678910

  • Hint

30%的数据满足1≤ N ≤1000000
100%的数据满足1≤ N ≤10^18且1≤ M ≤10^9


  • 分析

30%暴力,顺着题意模拟即可。
100%我们发现对于一段数位相等的数,每次操作就是把原数乘k(k位数)再加上一个k位数,这样我们可以构造一个矩阵快速乘,把时间降到log级别。然后分段(1~9、10~99……)处理。


一年前的代码
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <ctime>
#include <cmath>
#include <map>
using namespace std;
long long n,m,ans[4],i;
void mi(long long x10,long long times){
    x10%=m;
    long long a[4][4]={{0,0,0,0},{0,x10,0,0},{0,1,1,0},{0,1,1,1}};  
    long long b[4][4]={{0,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
    long long s[4][4];
    for (;times;times>>=1){
        if (times%2==1){
            for (long long i=1;i<=3;i++){
                for (long long j=1;j<=3;j++){
                    s[i][j]=((b[i][1]%m*a[1][j]%m)%m+(b[i][2]%m*a[2][j]%m)%m+(b[i][3]%m*a[3][j]%m)%m)%m;
                }
            }
            for (long long i=1;i<=3;i++){
                for (long long j=1;j<=3;j++){
                    b[i][j]=s[i][j];
                }
            }
        }
        for (long long i=1;i<=3;i++){
            for (long long j=1;j<=3;j++){
                s[i][j]=((a[i][1]%m*a[1][j]%m)%m+(a[i][2]%m*a[2][j]%m)%m+(a[i][3]%m*a[3][j]%m)%m)%m;
            }
        }
        for (long long i=1;i<=3;i++){
            for (long long j=1;j<=3;j++){
                a[i][j]=s[i][j];
            }
        }
    }
    s[1][1]=((ans[1]*b[1][1]%m)%m+(ans[2]%m*b[2][1]%m)%m+(ans[3]%m*b[3][1]%m)%m)%m;
    s[2][1]=ans[1]*b[1][2]+ans[2]*a[2][2]+ans[3]*b[3][2];
    s[3][1]=ans[1]*b[1][3]+ans[2]*a[2][3]+ans[3]*b[3][3];
    ans[1]=s[1][1]; ans[2]=s[2][1]; ans[3]=s[3][1];
}
int main(){
    freopen("homework.in","r",stdin);
    freopen("homework.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    ans[1]=ans[2]=0;ans[3]=1;
    for (i=10;i<=n;i*=10){
        mi(i,9*i/10);
    }
    mi(i,n-(i/10)+1);
    printf("%d",ans[1]);
    fclose(stdin); fclose(stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值