题目描述
DP
考虑每个位置的贡献。
枚举一个位置,然后做dp,我们需要处理从(0,0)走k步到这个位置的方案数(中途不到达这个位置),以及从这个位置开始走k步到某个位置的方案数(中途不到达这个位置),以及从这个位置开始走k步中途不到达自己的方案数。
然后再做dp,从(0,0)走j步到达这个位置且中间恰好经过它k次的方案数。
#pragma GCC optimize (2)
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=60+10,mo=998244353,mx=30;
int g[maxn][maxn],f[maxn][maxn][maxn],ff[maxn][maxn][maxn],h[maxn][maxn][maxn],hh[maxn][maxn][maxn];
int fx[4][2];
bool bz[maxn][maxn],pd[maxn][maxn];
int i,j,k,l,t,T,K,n,m,ans;
void work(int x,int y){
int i,j,k,l,xx,yy;
fo(i,-T,T)
fo(j,-T,T)
if (pd[i+mx][j+mx])
fo(k,0,T)
f[i+mx][j+mx][k]=0;
f[x+mx][y+mx][0]=1;
fo(k,0,T)
fo(i,-T,T)
fo(j,-T,T)
if (pd[i+mx][j+mx]&&!bz[i+mx][j+mx])
if (f[i+mx][j+mx][k]&&(k==0||i!=x||j!=y)){
(hh[x+mx][y+mx][k]+=f[i+mx][j+mx][k]);
if (hh[x+mx][y+mx][k]>=mo) hh[x+mx][y+mx][k]-=mo;
if (k==T) continue;
fo(l,0,3){
xx=i+fx[l][0];yy=j+fx[l][1];
(f[xx+mx][yy+mx][k+1]+=f[i+mx][j+mx][k]);
if (f[xx+mx][yy+mx][k+1]>=mo) f[xx+mx][yy+mx][k+1]-=mo;
}
}
fo(k,0,T){
h[x+mx][y+mx][k]=f[x+mx][y+mx][k];
ff[x+mx][y+mx][k]=f[0+mx][0+mx][k];
}
}
void calc(int x,int y){
int i,j,k;
fo(i,0,T)
fo(j,0,T+1)
g[i][j]=0;
fo(i,0,T){
if (!i||x||y) g[i][1]=ff[x+mx][y+mx][i];
fo(j,2,i+1)
fo(k,0,i-1){
(g[i][j]+=(ll)g[k][j-1]*h[x+mx][y+mx][i-k]%mo);
if (g[i][j]>=mo) g[i][j]-=mo;
}
fo(j,K,i+1){
(ans+=(ll)g[i][j]*hh[x+mx][y+mx][T-i]%mo);
if (ans>=mo) ans-=mo;
}
}
}
int main(){
freopen("wander.in","r",stdin);freopen("wander.out","w",stdout);
fx[0][0]=1;fx[0][1]=0;
fx[1][0]=-1;fx[1][1]=0;
fx[2][0]=0;fx[2][1]=1;
fx[3][0]=0;fx[3][1]=-1;
scanf("%d%d%d",&T,&n,&K);
fo(i,-T,T)
fo(j,-T,T)
if (abs(i)+abs(j)<=T) pd[i+mx][j+mx]=1;
fo(i,1,n){
scanf("%d%d",&j,&k);
bz[j+mx][k+mx]=1;
}
fo(i,-T,T)
fo(j,-T,T){
if (pd[i+mx][j+mx]&&!bz[i+mx][j+mx]){
work(i,j);
calc(i,j);
}
}
//(ans+=mo)%=mo;
printf("%d\n",ans);
}