HDU5564 Clarke and digits
阿新 • • 發佈:2019-02-17
個數 dig 表示 hdu clas 構建 問題 inline span 的轉移矩陣。
前置知識
\(dp[i][j][k]\)表示\(i\)長,\(mod7=j\),這個位置選了\(k\)的方案數。
\(dp[i+1][(j*10+x)mod7][x]+=dp[i][j][y];//x+y!=K?\)
\(Ma.a[i][j]=1\)表示\(i\)狀態->\(j\)狀態可以轉移
如果設\(ans=qkpow(Ma,K)\)。
則\(ans.a[i][j]\)表示走\(K\)步之後狀態\(i\)到狀態\(j\)的方案數。
如果對這個不熟悉可以看看HDU5607
題解
然後對於本題而言,就要構建轉移的矩陣。
註意到對於後兩維而言,其實他們的轉移都是一樣的,與\(i\)沒有關系,而且其狀態只有7*10,所以可以構建\(70·70\)
初始矩陣就是第一位隨便填哪個數字都無所謂,所以
for(int i=1;i<10;i++)
s.a[0][st(i%7,i)]=1;
接下來還有一個問題:如何統計前綴和?
我們要求的不僅僅是\(ans(R),ans(L)\)而是\(\sum_{i=L}^Rans(i)\)
所以,這裏有一個巧妙的操作:
for(int i=0;i<10;i++)
Ma.a[i][70]=1;
Ma.a[70][70]=1;
這樣就可以保證我們最後要求的\(ans=\sum_{i=0}^9a[0][i]\)每一層都會被加到70這個點上,所以最後\(a[0][70]\)就是答案。
代碼
#include<bits/stdc++.h> #define M 105 using namespace std; const int mod=1e9+7; int l,r,K,T; struct Matrix{ int n,m,a[M][M]; void clear(){memset(a,0,sizeof(a));} void resize(int _n,int _m){n=_n;m=_m;} Matrix operator *(const Matrix &_)const{ Matrix res;res.resize(n,_.m); for(int i=0;i<=n;i++){ for(int j=0;j<=_.m;j++){ res.a[i][j]=0; for(int k=0;k<=m;k++){ res.a[i][j]+=1LL*a[i][k]*_.a[k][j]%mod; if(res.a[i][j]>=mod)res.a[i][j]-=mod; } } } return res; } }Ma,s; Matrix qkpow(Matrix a,int b){ Matrix res;res.clear();res.resize(a.n,a.n); for(int i=0;i<=a.n;i++)res.a[i][i]=1; while(b){if(b&1)res=res*a;a=a*a;b>>=1;} return res; } int st(int i,int j){return i*10+j;} int main(){ cin>>T; s.clear();s.resize(70,70); for(int i=1;i<10;i++) s.a[0][st(i%7,i)]=1; while(T--){ scanf("%d%d%d",&l,&r,&K); Ma.clear();Ma.resize(70,70); for(int y=0;y<10;y++){ for(int x=0;x<10;x++){ if(x+y==K)continue; for(int j=0;j<7;j++){ Ma.a[st(j,y)][st((j*10+x)%7,x)]=1; } } } for(int i=0;i<10;i++) Ma.a[i][70]=1; Ma.a[70][70]=1; Matrix R=s*qkpow(Ma,r); Matrix L=s*qkpow(Ma,l-1); printf("%d\n",(R.a[0][70]-L.a[0][70]+mod)%mod); } return 0; }
HDU5564 Clarke and digits