【bzoj】2326 [HNOI2011]數學作業
阿新 • • 發佈:2018-04-10
gif 高位到低位 algo space n) n+1 const std class
【題意】給定n和m,求1~n從高位到低位連接%m的結果。n=11時,ans=1234567891011%m。n<=10^18,m<=10^9。
【算法】遞推+矩陣快速冪
【題解】
考慮枚舉位數個數k,對於不同的k單獨遞推,設f[i]表示1~i的答案,則有:
$$f_n=f_{n-1}*10^k+i$$
轉化為矩陣遞推式,則有:
$$\begin{vmatrix}10^k & 1 & 1\\ 0 & 1 & 1\\0 & 0 & 1\end{vmatrix} \times \begin{vmatrix}f_n \\ n\\1 \end{vmatrix}=\begin{vmatrix}f_{n+1}\\n+1\\1\end{vmatrix}$$
轉化為冪形式,則有:
$$\begin{vmatrix}10^k & 1 & 1\\ 0 & 1 & 1\\0 & 0 & 1\end{vmatrix}^n \times \begin{vmatrix}f_i \\ i\\1 \end{vmatrix}=\begin{vmatrix}f_{i+n}\\i+n\\1\end{vmatrix}$$
分段進行矩陣快速冪即可。
註意讀入的n是long long。
#include<cstdio> #include<cstring> #include<algorithm> #defineView Codell long long using namespace std; const int N=3; int c[N][N],ANS[N][N],A[N][N],m; ll n;/// void multply(int a[N][N],int b[N][N]){ for(int i=0;i<=2;i++){ for(int j=0;j<=2;j++){ c[i][j]=0; for(int k=0;k<=2;k++){ c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j]%m)%m; } } }for(int i=0;i<=2;i++)for(int j=0;j<=2;j++)b[i][j]=c[i][j]; } void solve(ll p,int &f,int x,int k){ memset(A,0,sizeof(A)); A[0][1]=A[0][2]=A[1][1]=A[1][2]=A[2][2]=1;A[0][0]=k; ANS[0][0]=f;ANS[1][0]=x%m;ANS[2][0]=1; while(p){ if(p&1)multply(A,ANS); multply(A,A); p>>=1; } f=ANS[0][0]; } int main(){ scanf("%lld%d",&n,&m); ll x=0,y=9; int k=10%m,ans=0; while(x+y<n){ solve(y,ans,x%m,k);// x+=y;y*=10;k=1ll*k*10%m; } solve(n-x,ans,x%m,k); printf("%d",ans%m); return 0; }
【bzoj】2326 [HNOI2011]數學作業