(多校)棋盘
可以暴力 \(dp\) ,但每次转移时我们发现有许多转移是多余的
考虑 \(dp\) 的重复利用
首先如果把起点设在 \(l\) 位置肯定是不行的
其实不难发现,从上面某一点走到下面某一点的反方案与正方案基本相同
所以我们可以构造一个中途转移点,当新添加一行时,直接更新新的 \(dp\) 值
当 \(l\) 删到 转移点 时,把转移点重设为 \(r\) ,再更新一边 \(dp\) 数组即可
注意到每个位置最多会被重构一次,所以复杂度可以得到保证
但考虑另外一种情况
我们上面的转移是一定经过转移点的,所以我们再另开一个数组,把该数组的转移点设为 原转移点 \(-1\)
同理维护即可
Code
#include<bits/stdc++.h>
#define re register
// #define int long long
#define lls long long
#define fr first
#define sc second
#define pb push_back
using namespace std;
const int mol=998244353;
const int maxn=1e5+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
int w=1,s=0; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
int l=1,r,mid;
char opt[10],mapp[maxn][26];
int n,m,f[maxn][26][26],g[maxn][26][26];
inline void ad(int &x) { x=x>=mol?x-mol:x; }
inline void getf(int now,int l1,int l2) {
memset(f[now],0,sizeof(f[now]));
for(re int i=1;i<=n;i++) if(mapp[now][i]=='.') {
for(re int j=1;j<=n;j++) {
if(i+2<=n) ad(f[now][i][j]+=f[l1][i+2][j]);
if(i-2>=1) ad(f[now][i][j]+=f[l1][i-2][j]);
if(i+1<=n) ad(f[now][i][j]+=f[l2][i+1][j]);
if(i-1>=1) ad(f[now][i][j]+=f[l2][i-1][j]);
}
}
}
inline void getg(int now,int l1,int l2) {
memset(g[now],0,sizeof(g[now]));
for(re int i=1;i<=n;i++) if(mapp[now][i]=='.') {
for(re int j=1;j<=n;j++) {
if(i+2<=n) ad(g[now][i][j]+=g[l1][i+2][j]);
if(i-2>=1) ad(g[now][i][j]+=g[l1][i-2][j]);
if(i+1<=n) ad(g[now][i][j]+=g[l2][i+1][j]);
if(i-1>=1) ad(g[now][i][j]+=g[l2][i-1][j]);
}
}
}
inline void rebuild() {
mid=r;
memset(f[mid],0,sizeof(f[mid]));
memset(g[mid-1],0,sizeof(g[mid-1]));
for(re int i=1;i<=n;i++) if(mapp[mid][i]=='.') f[mid][i][i]=1;
for(re int i=r-1;i>=l;i--) { getf(i,i+1, i+2<=mid? i+2:0 ); }
if(l==r) return;
for(re int i=1;i<=n;i++) if(mapp[mid-1][i]=='.') g[mid-1][i][i]=1;
for(re int i=r-2;i>=l;i--) { getg(i,i+1, i+2<mid? i+2:0 ); }
}
signed main(void) {
freopen("erp.in","r",stdin); freopen("erp.out","w",stdout);
n=read(); m=read();
for(re int t=1;t<=m;t++) {
scanf("%s",opt+1);
if(opt[1]=='A') {
scanf("%s",mapp[++r]+1);
if(l>mid) { rebuild(); continue; }
getf(r,r-1, r-2>=mid? r-2:0 );
if(r==mid+1) {
for(re int i=1;i<=n;i++) if(mapp[r][i]=='.') g[r][i][i]=1;
} else {
getg(r,r-1, r-2>mid? r-2:0 );
}
}
if(opt[1]=='D') {
l++; if(l>mid) rebuild();
}
if(opt[1]=='Q') {
int ans=0; int x=read(),y=read();
if(l==r&&x!=y) { puts("0"); continue; }
if(l==r&&x==y) { puts("0"); continue; }
for(re int i=1;i<=n;i++) ad(ans+=(lls)f[l][x][i]*f[r][y][i]%mol);
if(l<mid&&r>mid)
for(re int i=1;i<=n;i++) {
ad(ans+=(lls)(i+1<=n)*g[l][x][i]*g[r][y][i+1]%mol);
ad(ans+=(lls)(i-1>=1)*g[l][x][i]*g[r][y][i-1]%mol);
}
printf("%d\n",ans);
}
}
}