【bzoj2326】【HNOI2011】【数学作业】

2326: [HNOI2011]数学作业

Time Limit: 10 Sec Memory Limit: 128 MB

Submit: 1264 Solved: 727

[Submit][Status][Discuss]

Description

思路:其实很容易可以想到,当我们所要连接的数的位数不同的时候,我们需要把原来的数增大的倍数是不一样的。

所以我们需要分阶段来做矩乘。

根据数的位数分为1->9;10->99………10^k->10^(k+1)-1;就可以了。

但是我们还需要注意一个问题,就是由于我们每个阶段快速幂的矩阵是不一样的,所以每个阶段做完以后我们都需要跟新答案,因为矩乘没有分配率!!

这样以后我们就可以做了,矩阵是:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,a[3][3],c[3][3],ans[3][3],aa[3],bb[3];
long long quickcheng(long long x,long long y)
{
    long long out=0;
    x=x%m;y=y%m;
    if(x>y) swap(x,y);
    while(y)
    {
        if(y&1) out=(out+x)%m;
        y>>=1;
        x=(x+x)%m;
    }
    return out;
}
void mul(long long x,long long z)
{
    long long y=z-x/10+1,i,j,k;
    bool f=true;
    if(x==10) y-=1;
    a[0][0]=x;
    a[0][1]=a[1][1]=a[1][2]=a[2][2]=1;
    a[0][2]=a[1][0]=a[2][0]=a[2][1]=0;
    while(y){
        if(y&1){
            if(f){
                for(i=0;i<=2;++i)
                  for(j=0;j<=2;++j)
                    ans[i][j]=a[i][j];
                f=false;
            }
            else{
                for(i=0;i<=2;++i)
                  for(j=0;j<=2;++j){
                    c[i][j]=0;
                    for(k=0;k<=2;++k)
                      c[i][j]=(c[i][j]+quickcheng(a[i][k],ans[k][j]))%m;
                  }
                for(i=0;i<=2;++i)
                  for(j=0;j<=2;++j)
                    ans[i][j]=c[i][j];
            }
        }
        y>>=1;
        for(i=0;i<=2;++i)
          for(j=0;j<=2;++j){
            c[i][j]=0;
            for(k=0;k<=2;++k)
              c[i][j]=(c[i][j]+quickcheng(a[i][k],a[k][j]))%m;
          }
        for(i=0;i<=2;++i)
          for(j=0;j<=2;++j)
            a[i][j]=c[i][j];
    }
    for(i=0;i<=2;++i){
        bb[i]=0;
        for(j=0;j<=2;++j){
            bb[i]=(bb[i]+quickcheng(ans[i][j],aa[j]))%m;
        }
   }
   for(i=0;i<=2;++i)
     aa[i]=bb[i];
}
int main()
{
    long long t=10;
    cin>>n>>m;
    aa[0]=1;aa[1]=2;aa[2]=1;
    while(n>=t){
        mul(t,t-1);
        t*=10;
    }
    mul(t,n);
    cout<<aa[0]<<endl;
}
时间: 2024-10-13 11:35:01

【bzoj2326】【HNOI2011】【数学作业】的相关文章

BZOJ2326 HNOI2011 数学作业 矩阵乘法

题意:求12345……101112……(N-1)N mod M的值(被模数就是1-N顺次连接起来). 题解:丧病的数学老师,看自己写的题解都看不懂了QAQ,首先设${f_i}$=前i个数连接起来 mod M的值,然后按位数不断转移,也就是说,假定当前要增加的数i最高位是10^k,那么\[{f_i} = ({10^{k + 1}}{f_{i - 1}} + i)\bmod M\] 所以\[\left( {\begin{array}{*{20}{c}}{{f_{{{10}^{k + 1}} - 1}

bzoj2326 [HNOI2011]数学作业

分析:设f[i]为1~i组成的数,可以得到f[i] = f[i-1] * 10^k + i.对于一个序列求第n项,一般可以用矩阵乘法来加速,但是每一个矩阵只能对应一个不变的递推式,这个式子中的k会变,那怎么办呢?那么在1~9,10~99,100~999每一次构造一个矩阵就好了,具体的矩阵如下: f(i + 1)       f(i)  10^k,1,1 i        =     i - 1    *    0, 1, 1 1   1 0, 0, 1 #include <cstdio> #i

bzoj2326:[HNOI2011]数学作业(分段矩阵乘法)

题目大意:输入n(n<=10^18)和m,将1~n的整数连起来模m输出,比如n=13则输出12345678910111213模m的数. 设f[i]为1~i整数连起来模m的数,i的位数为k,则有f[i]=(f[i-1]*10^k+i)mod m.可以发现f[i-1]和10^k都是会变化的,不能直接矩乘,这就尴尬了>_<.但是仔细想想(跑去问CZL),其实可以分段来矩乘,把k一样的数矩乘(1..9一样,10..99一样,100..999一样)就行了. orz CZL初二的时候1A,然而我却W

【矩阵乘法】bzoj2326 [HNOI2011]数学作业

http://hzwer.com/2831.html #include<cstdio> #include<iostream> #include<vector> using namespace std; typedef long long ll; typedef vector<ll> vec; typedef vector<vec> mat; ll n,MOD; mat operator * (const mat &a,const mat

【BZOJ2326】[HNOI2011]数学作业 矩阵乘法

[BZOJ2326][HNOI2011]数学作业 题解:对于位数相同的数字,这显然是满足矩乘性质的. 那么我们枚举每一位,如果当前i=10^k,那么维护行向量(sum,now,1),now代表当前的数,每次将sum*=i再加上now,now+=1即可. #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; ll n,P; st

矩阵乘法专题4——bzoj 2326 [HNOI2011] 数学作业 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24963747 [原题] 2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 853  Solved: 473 [Submit][Status] Description [分析]我们按数字的位数来划分.对于K位数,我们就可以专门设计一个矩阵来计算. 然后就是注意细节了. [代码] #include

2326: [HNOI2011]数学作业

2326: [HNOI2011]数学作业 Description 不说什么ACTY了.. 题解: 线性的递推很容易写出来,f[i]=f[i-1]*10+i  (mod) 但是n很大,就需要用到矩阵乘法了.. 我们够造矩阵 10^i   0       0       f[i-1]        f[i] 1        1       0   *   i-1     =    i 1        1       1        1             1 #include<stdio.

【BZOJ 2326】 [HNOI2011]数学作业

2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1100  Solved: 625 [Submit][Status] Description 矩阵乘法. 可以用类似于秦九韶算法,把被取模的数拆开. 如123%m=(((1%m)*10+2)%m*10+3)%m 我们发现对于位数相同的数的计算方法是一样的,想到矩阵乘法. 对于1位的数: matrix x=10^1  0  0 1       1  0 0  

洛谷P3216 [HNOI2011]数学作业

洛谷P3216 [HNOI2011]数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 ..N)是将所有正整数 1, 2, -, N 顺序连接起来得到的数.例如,N = 13, Concatenate (1 .. N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,

[HNOI2011]数学作业

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