解析
不难发现有效的状态只有
S
=
C
11
3
=
165
S=C_{11}^3=165
S=C113=165 种。
同时,能支持
n
=
1
0
18
n=10^{18}
n=1018 的算法也不剩啥了,要么拉插,要么矩乘。
本题当然就是矩乘了,转移矩阵也较为显然。
然而,直接做的话复杂度是 O ( T S 3 log n ) O(TS^3\log n) O(TS3logn) 的,只有 60pts。
然后就有一个很简单但效果非常显著的优化:每次不再像正常矩阵快速幂一样求出转移矩阵的 n n n 次方,而是预处理出所有 2 i 2^i 2i 的转移矩阵,然后把答案行矩阵和需要的转移矩阵分别乘即可,复杂度 O ( T S 2 log n ) O(TS^2\log n) O(TS2logn)。
不要僵化思维!
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;
const int N=2050;
const double eps=1e-10;
const int mod=998244353;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline ll ksm(ll x,ll k){
ll res(1);
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int n,m,k;
struct matrix{
ll a[205][205];
int x,y;
matrix(int X=0,int Y=0):x(X),y(Y){memset(a,0,sizeof(a));}
};
matrix operator * (const matrix &u,const matrix &v){
matrix res(u.x,v.y);
for(int k=1;k<=u.y;k++){
for(int i=1;i<=u.x;i++){
ll tmp=u.a[i][k];
for(int j=1;j<=v.y;j++){
(res.a[i][j]+=tmp*v.a[k][j])%=mod;
}
}
}
return res;
}
int id[10][10][10],tot;
struct state{
int x,y,z;
};
matrix mi[100];
matrix calc(ll k){
matrix res(tot+1,tot+1);
for(int i=1;i<=tot+1;i++) res.a[i][i]=1;
int cnt(0);
while(k){
if(k&1) res=res*mi[cnt];
cnt++;
k>>=1;
}
return res;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int T=read();m=read();k=read();
for(int i=0;i<=k;i++){
for(int j=0;i+j<=k;j++){
for(int p=0;i+j+p<=k;p++){
id[i][j][p]=++tot;
//printf("(%d %d %d) id=%d\n",i,j,p)
if(m<=2) break;
}
if(m<=1) break;
}
}
matrix trans(tot+1,tot+1);
for(int a=0;a<=k;a++){
for(int b=0;a+b<=k;b++){
for(int c=0;c<=k;c++){
int add2=(m==2&&min(1,k-a-b-c)),add3=(m==3&&min(1,k-a-b-c)),now=id[a][b][c];
if(!now) continue;
ll p=ksm(a+b+c+1,mod-2);
trans.a[tot+1][now]=trans.a[now][now]=p;
if(a) trans.a[ id[a-1][b][c] ][now]=p*a%mod;
if(b) trans.a[ id[a+1][b-1+add2][c+add3] ][now]=p*b%mod;
if(c) trans.a[ id[a][b+1+add2][c-1+add3] ][now]=p*c%mod;
}
}
}
trans.a[tot+1][tot+1]=1;
int s;
if(m==1) s=id[1][0][0];
if(m==2) s=id[0][1][0];
if(m==3) s=id[0][0][1];
mi[0]=trans;
for(int i=1;i<=60;i++) mi[i]=mi[i-1]*mi[i-1];
matrix ori(1,tot+1);
ori.a[1][tot+1]=1;
while(T--){
ll n=read();
int cnt(0);
matrix res=ori;
while(n){
if(n&1) res=res*mi[cnt];
++cnt;
n>>=1;
}
printf("%lld\n",res.a[1][s]);
}
return 0;
}