有一副紙牌。牌一共有 $n$ 種,分別標有 $1, 2, \dots , n$,每種有 $C$ 張。故這副牌共有 $nC$ 張。c++
三張連號的牌($i, i+1, i+2$)或三張相同的牌 $(i,i,i)$ 能夠組成一疊。若是一組牌能夠分紅若干(包括零)疊,就稱其爲一組王牌。git
你從牌堆中摸了一些初始牌。如今你想再挑出一些牌組成一組王牌,請問有多少種可能組成的王牌呢?答案對 $998244353$ 取模。ide
兩組牌相同當且僅當它們含有的每一種牌數量都相同。ui
看到數據範圍 $n\le 1e^{18}$ 大概猜到對於沒有初始牌的牌堆要麼有顯然規律,要麼就是矩乘。spa
對而後就矩乘了。code
由於大於等於 $3$ 張的,咱們能夠在本身牌堆裏本身湊成一組,對於要和其餘種牌配對的只須要留至多比前一堆多三張的狀況。blog
因此咱們能夠用一個 $3*3$ 的狀態表示最後兩個牌堆的狀況。get
而後用矩陣表示狀態的轉移係數。it
對於有初始牌的單獨構造矩陣。event
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1005,p=998244353; int c,m,a[N],Lg;LL k[N],n; il LL read(){ LL x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } struct Mat{ int a[11][11]; Mat friend operator *(Mat t1,Mat t2){ Mat t3; for(int i=0;i<9;i++)for(int j=0;j<9;j++)t3.a[i][j]=0; for(int i=0;i<9;i++)for(int j=0;j<9;j++)for(int k=0;k<9;k++) t3.a[i][j]=mu(t3.a[i][j],1ll*t1.a[i][k]*t2.a[k][j]%p); return t3; } }Ans,po[70],tmp; il void ksm(LL y){ for(int i=0;i<=Lg;i++)if((1ll<<i)&y)Ans=Ans*po[i]; } int main() { n=read();c=read();m=read();Lg=log2(n)+1; for(int i=1;i<=m;i++)k[i]=read(),a[i]=read(); for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++) if(i+j+k<=c)po[0].a[i*3+j][j*3+k]=(c-i-j-k)/3+1; for(int i=1;i<=Lg;i++)po[i]=po[i-1]*po[i-1]; Ans.a[0][0]=1; for(int x=1;x<=m;x++){ ksm(k[x]-k[x-1]-1);//printf("!!%d ",Ans.a[0][0]); for(int i=0;i<9;i++)for(int j=0;j<9;j++)tmp.a[i][j]=0; for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++){ int now=i+j+k; if(now<a[x])now=a[x]+((now-a[x])%3+3)%3; if(now<=c)tmp.a[i*3+j][j*3+k]=(c-now)/3+1; } Ans=Ans*tmp; } ksm(n-k[m]); printf("%d\n",Ans.a[0][0]); return 0; }