小C有一个 $n $ 列的棋盘,一开始是空的,棋盘上可能会有一些障碍无法通过
小C要对它进行了 \(q\) 次操作,每次操作为以下三种操作之一
Add
:在棋盘末尾加入了一行Del
:删除棋盘的第一行Que
: 询问:有一只马从当前棋盘的第一行第ii列出发,要到最后一行第jj列。每次只能向棋盘的下方走,询问合法的方案数\(\mod 998244353\) .**如果棋盘为空,起点或者终点有障碍,均输出 \(0\) **
一只马 \((x,y)\) 的活动范围是 \((x+1,y-2),(x+1,y+2),(x+2,y-1),(x+2,y+1)\)
\(1\leq n\leq 20,\ q\leq 100000\)
时限 : 1s
空限 : 1024mb
这个过程特别像双端队列,于是联想到上次模拟的一题,nflsoj 20034 #10232「2019五校联考-镇海3」小 ω 的仙人掌 .
可以用两个栈来维护 \(dp\) .
第一栈维护从后往前,第二个栈维护从前往后 .
但是,这个题目还有一个问题,就是马可以跳两层,需要维护两个 \(dp\) ,第一个是 \([l,x]\) 与 \([x+1,r]\) ,第二个是 \([l,x+1]\) 与 \([x+1,r]\) .
但是,计算的时候还是会算重,需要减掉重复的部分,就是从 \(x\) 行跳到 \(x+1\) 行的方案数 .
细节有亿点多 .
时间复杂度 : \(\mathrm O(qn^2)\)
空间复杂度 : \(\mathrm O(qn^2)\)
code
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,q;
string s[100010];
int f1[22][100010][22],g1[22][100010][22];
int f2[22][100010][22],g2[22][100010][22];
inline void upd(int &x,int y){x=(x+y)%mod;}
void nx(int g[22][100010][22],string board,int l,int tmp){
for(int i=0;i<n;i++)for(int j=0;j<n;j++){
g[i][tmp][j]=0;
if(board[j]=='#')continue;
if(j+2<n&&tmp-1>=l)upd(g[i][tmp][j],g[i][tmp-1][j+2]);
if(j-2>=0&&tmp-1>=l)upd(g[i][tmp][j],g[i][tmp-1][j-2]);
if(j+1<n&&tmp-2>=l)upd(g[i][tmp][j],g[i][tmp-2][j+1]);
if(j-1>=0&&tmp-2>=l)upd(g[i][tmp][j],g[i][tmp-2][j-1]);
}
}
void pr(int f[22][100010][22],int now,int st){
for(int i=0;i<n;i++)for(int j=0;j<n;j++)f[i][now][j]=0;
for(int i=0;i<n;i++)if(s[now][i]=='.')f[i][now][i]=1;
for(int i=0;i<n;i++)for(int k=now-1;k>=st;k--)for(int j=0;j<n;j++){
f[i][k][j]=0;
if(s[k][j]=='#')continue;
if(k+1<=now&&j+2<n)upd(f[i][k][j],f[i][k+1][j+2]);
if(k+1<=now&&j-2>=0)upd(f[i][k][j],f[i][k+1][j-2]);
if(k+2<=now&&j+1<n)upd(f[i][k][j],f[i][k+2][j+1]);
if(k+2<=now&&j-1>=0)upd(f[i][k][j],f[i][k+2][j-1]);
}
}
int main(){
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
cin>>n>>q;
int st=1,ed=0,now=0;
for(int t=0;t<q;t++){
string type;
cin>>type;
if(type[0]=='A'){
ed++;
cin>>s[ed];
if(st==ed){
for(int i=0;i<n;i++)for(int j=0;j<n;j++){
f1[i][st][j]=g1[i][st][j]=0;
}
for(int i=0;i<n;i++)if(s[ed][i]=='.')f1[i][st][i]=g1[i][st][i]=1;
now=st;
}else{
nx(g1,s[ed],now,ed);
if(st<now)nx(g2,s[ed],now-1,ed);
}
}else if(type[0]=='D'){
st++;
if(st>now){
now=ed;
if(st>ed)continue;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)g1[i][ed][j]=0;
for(int i=0;i<n;i++)if(s[ed][i]=='.')g1[i][ed][i]=1;
pr(f1,now,st);
if(now>st){
pr(f2,now-1,st);
for(int i=0;i<n;i++)for(int j=0;j<n;j++)g2[i][now-1][j]=0;
for(int i=0;i<n;i++)if(s[now-1][i]=='.')g2[i][now-1][i]=1;
nx(g2,s[ed],now-1,ed);
}
}
}else{
int x,y;
cin>>x>>y;
x--;y--;
if(st>now)cout<<"0\n";
else if(st==now)cout<<g1[x][ed][y]<<"\n";
else{
int ans=0;
for(int i=0;i<n;i++){
upd(ans,1ll*f1[i][st][x]*g1[i][ed][y]%mod);
upd(ans,1ll*f2[i][st][x]*g2[i][ed][y]%mod);
}
for(int i=0;i<n;i++){
if(i+2<n)upd(ans,(mod-1ll*f2[i][st][x]*g1[i+2][ed][y]%mod)%mod);
if(i-2>=0)upd(ans,(mod-1ll*f2[i][st][x]*g1[i-2][ed][y]%mod)%mod);
}
cout<<ans<<"\n";
}
}
}
return 0;
}