題解
其實這題很容易想到狀壓dp,設爲當前還有點傷害需要釋放,並且敵人目前戰況爲時對Boss造成傷害的期望值
特別大怎麼辦?矩陣快速冪!
根據數學推導,設爲戰況的總數,則,複雜度
等等!這樣不會超時嗎?
考慮做一個小優化:首先,矩陣乘法的複雜度其實是,不一定是
而一個方陣乘一個向量是的
所以可以利用這個特性,預處理矩陣的次冪,每次查詢時找出需要的那些矩陣即可
類似的方法可用於矩陣快速冪的題目中查詢特別多的情況,複雜度
這題特別卡常(我最後一個點TLE了好幾次),具體實現時可以參照我的代碼中的一些小優化
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll p=998244353,P=(0x7fffffffffffffffll/p-p)*p,N=170;
ll q,n,m,k,m1,x[20],y[20],first;
ll a[N];
void upd(ll &a,ll b){a+=b;if(P<=a)a-=P;}//卡常優化:開大模數
ll hx(){
ll ans=0;
for(ll i=1;i<=m1;i++)(ans<<=1)|=x[i];
return ans;
}
void xh(ll h){
for(ll i=m1;i;i--)x[i]=h&1,h>>=1;
}
ll expo(ll a,ll b){
ll c=1;
while(b){
if(b&1)(c*=a)%=p;
(a*=a)%=p;
b>>=1;
}
return c;
}
ll inv(ll a){
return expo(a,p-2);
}
void dfs(ll l,ll t){
if(m1<l&&t==m)a[++n]=hx();
if(m1<l)return;
x[l]=0,dfs(l+1,t);
if(t<m)x[l]=1,dfs(l+1,t+1);
}
ll find(ll x){
return lower_bound(a+1,a+n+1,x)-a;
}
struct mat{
ll a[N][N];
mat mul(mat &b){
mat ans;
for(ll i=0;i<=n;i++)for(ll j=0;j<=n;j++)ans.a[i][j]=0;
for(ll i=0;i<=n;i++)for(ll k=0;k<=n;k++){
if(!b.a[i][k])continue;//卡常優化:由於矩陣是一個稀疏矩陣,所以可以直接跳過0
for(ll j=0;j<=n;j++)upd(ans.a[i][j],a[k][j]*b.a[i][k]);
}
for(ll i=0;i<=n;i++)for(ll j=0;j<=n;j++)ans.a[i][j]%=p;
return ans;
}
}ma,init[70];
struct vec{
ll a[N];
vec mul(mat &b){
vec ans;
for(ll i=0;i<=n;i++){
ans.a[i]=0;
for(ll k=0;k<=n;k++)upd(ans.a[i],a[k]*b.a[i][k]);
}
for(ll i=0;i<=n;i++)ans.a[i]%=p;
return ans;
}
}fs,ans;
int main(){
scanf("%lld%lld%lld",&q,&m,&k),m1=m+k;
dfs(1,0),ma.a[0][0]=fs.a[0]=1;
for(ll i1=1;i1<=n;i1++){
xh(a[i1]);
ll flag=1;
for(ll i=2;i<=m+1;i++)if(!x[i])flag=0;
if(flag)first=i1;
for(ll i=1;i<=m1;i++)y[i]=x[i];
ll tot=1;
for(ll i=1,j=m;j;j-=y[i++])tot+=y[i]^1;
tot=inv(tot);
ma.a[i1][0]=ma.a[i1][i1]=tot;
for(ll i=2;i<=m1;i++)if(y[i]&&(!y[i-1])){
ll tot2=0;
for(ll j=i-1;j&&!y[j];j--)tot2++;
for(ll j=1;j<=m1;j++)x[j]=y[j];
swap(x[i-1],x[i]);
ll flag=0;
for(ll j=i+1;j<=m1;j++)if(y[j])flag=1;
if(flag&&!y[m1]){for(ll j=m1;j!=1;j--)x[j]=x[j-1];x[1]=0;}
ma.a[i1][lower_bound(a+1,a+n+1,hx())-a]=tot*tot2%p;
}
}
init[0]=ma;
for(ll i=1;i<61;i++)init[i]=init[i-1].mul(init[i-1]);
while(q--){
ans=fs;
ll a,i=0;scanf("%lld",&a);
while(a){
if(a&1)ans=ans.mul(init[i]);++i;
a>>=1;
}
printf("%lld\n",ans.a[first]);
}
return 0;
}