傳送門
- 思路:暴力的做法就是枚舉末狀態,處理到末狀態的方案數
發現方案數只和有幾位不同有關,可以用分治 + dp 處理出 fi,j 表示和 i 有 j 位不同的數的和,複雜度 O(k2nk)
下面考慮處理係數,設 dpi,j 表示走 i 步,還有 j 個不同的方案數
那麼轉移可以表示成矩陣的形式,於是可以暴力前 2k 項跑 BM
處理出線性遞推式過後 bsgs,那麼最後的複雜度就是 O(qk2)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
namespace IO{
cs int Rlen=1<<22|1;
inline char gc(){
static char buf[Rlen],*p1,*p2;
(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
return p1==p2?EOF:*p1++;
}
int read(){
int x=0; char c=gc(); bool f=false;
while(!isdigit(c)) f=(c=='-'),c=gc();
while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
return f?-x:x;
}
} using namespace IO;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 1e6 + 5, M = 25;
int n, K, q, S, a[N];
int f[N][M];
void work(){
for(int i=0; i<S; i++) f[i][0]=a[i];
for(int i=1,u=1; i<S; i*=n, ++u){
for(int t=u; t>=1; t--)
for(int j=0; j<S; j+=i*n){
static int Sm[N];
memset(Sm,0,sizeof(int)*i);
for(int k=0; k<i; k++)
for(int l=j+k; l<j+i*n; l+=i) Add(Sm[k],f[l][t-1]);
for(int k=0; k<i*n; k++){
int coe=dec(Sm[k%i],f[j+k][t-1]);
Add(f[j+k][t],coe);
}
}
}
}
namespace BM{
int a[M<<2]; poly cur, bst; int vl=0, fail=0;
void operator += (poly &a, poly b){
if(a.size()<b.size()) a.resize(b.size());
for(int i=0; i<(int)b.size(); i++) Add(a[i],b[i]);
}
void extend(int n){
int t=a[n];
for(int i=1; i<(int)cur.size(); i++) Dec(t,mul(cur[i],a[n-i]));
if(!t) return;
if(cur.empty()){ cur.resize(n+1); fail=n; vl=t; return; }
int coe=mul(t,ksm(vl,Mod-2));
poly nxt(n-fail,0); nxt.pb(coe);
for(int i=1; i<(int)bst.size(); i++) nxt.pb(mul(coe,dec(0,bst[i])));
nxt+=cur;
if((int)cur.size()-n<=(int)bst.size()-fail) bst=cur, fail=n, vl=t;
cur=nxt;
}
}
cs int W = 1e3 + 50;
poly pw1[W], pw2[W], pw3[W], mod;
poly polymul(poly a, poly b){
int deg=a.size()+b.size()-1; poly c(deg,0);
for(int i=0; i<(int)a.size(); i++)
for(int j=0; j<(int)b.size(); j++)
Add(c[i+j],mul(a[i],b[j]));
for(int i=deg-1; i>=(int)mod.size()-1; i--) if(c[i]){
for(int j=mod.size()-2,k=i-1;~j;j--,k--)
Dec(c[k],mul(c[i],mod[j]));
} if(deg>mod.size()-1) c.resize(mod.size()-1); return c;
}
void work_BSGS(){
static int dp[M<<2][M];
int u=K+K+5; BM::a[1]=dp[0][0]=1;
BM::extend(1);
for(int i=1; i<=u; i++){
for(int j=0; j<=K; j++){
if(j) Add(dp[i][j],mul(dp[i-1][j-1],mul(K-j+1,n-1)));
Add(dp[i][j],mul(dp[i-1][j],mul(j,n-2)));
Add(dp[i][j],mul(dp[i-1][j+1],j+1));
} BM::a[i+1]=dp[i][0]; BM::extend(i+1);
} mod=BM::cur; reverse(mod.begin(),mod.end());
for(int i=0; i<(int)mod.size(); i++) mod[i]=dec(0,mod[i]);
mod.back()=1; assert(mod.size()<=K+5);
pw1[0].pb(1); pw1[1].pb(0); pw1[1].pb(1);
for(int i=2; i<=1000; i++) pw1[i]=polymul(pw1[i-1],pw1[1]);
pw2[0].pb(1); pw2[1]=pw1[1000];
for(int i=2; i<=1000; i++) pw2[i]=polymul(pw2[i-1],pw2[1]);
pw3[0].pb(1); pw3[1]=pw2[1000];
for(int i=2; i<=1000; i++) pw3[i]=polymul(pw3[i-1],pw3[1]);
}
int g[M][M<<1][M];
int main(){
#ifdef FSYolanda
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
#endif
n=read(), K=read(), q=read(); S=ksm(n,K);
for(int i=0; i<S; i++) a[i]=read();
work();
work_BSGS();
for(int T=0; T<=K; T++){
g[T][0][T]=1;
for(int i=1; i<(int)mod.size(); i++)
for(int j=0; j<=K; j++){
if(j) Add(g[T][i][j],mul(g[T][i-1][j-1],mul(K-j+1,n-1)));
Add(g[T][i][j],mul(g[T][i-1][j],mul(j,n-2)));
Add(g[T][i][j],mul(g[T][i-1][j+1],j+1));
}
}
int Ans=1;
while(q--){
int a=read(), T=mul(read(),Ans), t=T, ans=0;
poly coe=pw1[t%1000]; t/=1000;
coe=polymul(coe,pw2[t%1000]); t/=1000;
coe=polymul(coe,pw3[t]);
for(int i=0; i<=min(T,K); i++){
int as=0;
for(int j=0; j<(int)coe.size(); j++) if(coe[j])
Add(as,mul(coe[j],g[i][j][0]));
Add(ans,mul(f[a][i],as));
} cout<<(Ans=ans)<<'\n';
} return 0;
}