(多校)棋盘

可以暴力 \(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);
        }
    }
}
posted @ 2021-11-16 21:09  zJx-Lm  阅读(29)  评论(0编辑  收藏  举报