1. 程式人生 > >BZOJ2326: [HNOI2011]數學作業

BZOJ2326: [HNOI2011]數學作業

long long 包含 參考 problem 得到 n) family esp gpo

【傳送門: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; }

BZOJ2326: [HNOI2011]數學作業