【[HNOI2011]数学作业】

我又对着跑出正解的程序调了好久

怕不是眼瞎了

这就是个分段矩阵,我们很容易就得到了递推式

\[f[i]=f[i-1]*10^k+i$ 其中$k=log_{10}i$ 于是就是分段矩阵 ![矩阵](https://cdn.luogu.org/upload/pic/32564.png) 之后就是代码了,没有加快速乘WA了好久 ```cpp #include<iostream> #include<cstring> #include<cstdio> #define re register #define LL long long LL n,m; LL ans[4][4],a[4][4]; LL Ans=0; inline LL mul(LL a,LL b) { LL s=0; while(b) { if(b&1ll) s=s+a%m; b>>=1ll; a=a+a%m; } return s; } inline void did_a() { LL mid[4][4]; for(re int i=1;i<=3;i++) for(re int j=1;j<=3;j++) mid[i][j]=a[i][j],a[i][j]=0; for(re int i=1;i<=3;i++) for(re int j=1;j<=3;j++) for(re int p=1;p<=3;p++) a[i][j]=(a[i][j]+mul(mid[i][p],mid[p][j])%m)%m; } inline void did_ans() { LL mid[4][4]; for(re int i=1;i<=3;i++) for(re int j=1;j<=3;j++) mid[i][j]=ans[i][j],ans[i][j]=0; for(re int i=1;i<=3;i++) for(re int j=1;j<=3;j++) for(re int p=1;p<=3;p++) ans[i][j]=(ans[i][j]+mul(mid[i][p],a[p][j])%m)%m; } inline void Rebuild(LL t) { memset(a,0,sizeof(a)),memset(ans,0,sizeof(ans)); ans[1][1]=a[1][1]=1ll; ans[2][1]=a[2][1]=1ll; ans[2][2]=a[2][2]=1ll; ans[3][2]=a[3][2]=1ll; ans[3][3]=a[3][3]=t; } inline void Quick(LL b) { while(b) { if(b&1ll) did_ans(); b>>=1ll; did_a(); } } inline void work() { LL now=1; LL t=10; while(now<=n) { if(t<0) return; Rebuild(t); if(n>=t-1) Quick(t-1-now); else Quick(n-now); Ans=(ans[3][1]%m+mul(now,ans[3][2])%m+mul(Ans,ans[3][3])%m)%m; now=t; t*=10; } } int main() { scanf("%lld%lld",&n,&m); work(); printf("%lld\n",Ans); return 0; } ```\]

posted @ 2019-01-02 12:12  asuldb  阅读(196)  评论(0编辑  收藏  举报