zoukankan      html  css  js  c++  java
  • 某年元宵节大礼包 矩阵快速幂

    题目描述

      乐是做作业,给定正整数N,M,要求计算Concatenate(1……N)mod M的值,其中Concatenate是指将1到N拼起来得到的数。如N=13,Concatenate=12345678910111213

    输入格式

      一行两个整数,N,M

    输出格式

      一个非负整数表示计算结果

    样例

    输入  13 13

    输出  4

    数据范围

      n<=1018,m<=109

    分析

      第一眼看到这题:暴力模拟

      然后看到数据表示无语,1e18啊,这拼起来得多大

      不管了先弄一个模拟:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    unsigned long long s;
    int n, m;
    int wei(int x) {
        int s = 0;
        while (x) {
            s++;
            x /= 10;
        }
        return s;
    }
    int main() {
        freopen("le.in", "r", stdin);
        freopen("le.out", "w", stdout);
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
            s = (s * pow(10, wei(i)) + i),
            s = s % m;
        cout << s;
        return 0;
    }

      这个应该很好懂,就不解释了,30分

      作为一个合格的OI选手,一定是要考虑正解的。

    设ans[i]表示拼接到i位时的答案,我们很容易得到递推式:

      ans[i]=(ans[i-1]*p+i)%mod; 

    其中p表示当前i的位数乘十,先不考虑mod,比如ans[4]=123*10+4;

    于是这又是一个递推式问题,那么怎么办呢?暴力跑一遍?1e18的数据不TLE算我输

    所以这个时候矩阵快速幂来了……

    可以设一个矩阵A为

      {ans[i]  i  1} 反正我是习惯开一维数组。。。。

    然后另一个矩阵K为

      {p 0 0}

      {1 1 0}

      {1 1 1}

    这样A*K就能得到{ans[i]*p+i  i+1  1}即{ans[i+1]  i+1  1}

    是不是很巧妙,所以不难看出上述A中的1的作用——与ans[i],凑出ans[i+1]和i+1.

    接着考虑乘多少次方的问题,我们从i=0开始,如果n=4,那么显然要乘四次;

    如果n=14呢?从0到9,一共要乘9次,然后再从10到14乘5次

    接着多次进行迭代不难发现,我们可以用变量data拷贝n

    如果n>=p就乘9*p/10次,data减去乘的值

    当n<p时说明不够乘了,所以直接乘以data次

    最后跑快速幂就行了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ull;
    ull n,mod,a[4],c[4][4];
    void Mul(){
        ull cp[4];
        memset(cp,0,sizeof(cp));
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                cp[i]+=((a[j]%mod)*(c[j][i]%mod))%mod;
                //乘之前一定要mod一下不然两个数乘积可能超出longlong
                cp[i]%=mod;
            }  
        }
        memcpy(a,cp,sizeof(cp));
    }
    void Mulself(){
        ull cp[4][4];
        memset(cp,0,sizeof(cp));
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
                for(int k=1;k<=3;k++){
                    cp[i][j]+=((c[i][k]%mod)*(c[k][j]%mod))%mod;
                    cp[i][j]%=mod;
                }
        memcpy(c,cp,sizeof(cp));
    }
    int main(){
        scanf("%llu%llu",&n,&mod);
        a[1]=0;a[2]=0;a[3]=1;
        ull mx=n*10,data=n;
        for(ull p=10LL;p<=mx;p*=10LL){
            c[1][1]=p;c[1][2]=0;c[1][3]=0;
            c[2][1]=1;c[2][2]=1;c[2][3]=0;
            c[3][1]=1;c[3][2]=1;c[3][3]=1;
            ull x;
            if(n>=p){
                x=9LL*p/10LL;
                data-=x;
            }
            else x=data;
            while(x){
                if(x&1)Mul();
                x>>=1;
                Mulself();
            }
        }
        printf("%llu
    ",a[1]);
    }

     

     

  • 相关阅读:
    buuctf-web [强网杯 2019]随便注 1
    buuctf-crypto 引用可打印
    buuctf-crypto 变异凯撒
    buuctf-misc 文件中的秘密
    buuctf-misc LSB
    nginx 模块配置
    cloudflare CDN下nginx获取用户真实IP地址
    使用nginx后如何在web应用中获取用户ip及原理解释
    获取用户真实 ip 地址的 nginx 相关配置
    解决nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
  • 原文地址:https://www.cnblogs.com/anyixing-fly/p/12420244.html
Copyright © 2011-2022 走看看