Description
https://www.luogu.com.cn/problem/P10027
Solution
之前打比赛的时候细节都想到了,但是感觉不太好写。后面发现应该都从后转移就很好写了。
记 $f_{i,j,k}$ 表示在 $(i,j)$,回溯 $k$ 次回到这个位置的方案数。枚举最后一次从 $(i,j)$ 出发,有转移:
$$
f_{i,j,k}=\sum f_{i,j,t}\times(f_{i+1,j,k-t-1}+f_{i,j+1,k-t-1})
$$
记 $g_{i,j,k}$ 表示从 $(i,j)$ 到终点,回溯 $k$ 次到终点的方案数。枚举第一次在自身回溯,有转移:
$$
g_{i,j,k}=\sum f_{i,j,t}\times (g_{i+1,j,k-t}+g_{i,j+1,k-t})
$$
代码很好写也很短。复杂度 $O(nmk^2)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include<bits/stdc++.h> #define int long long #define ull unsigned long long #define maxn 105 #define put() putchar('\n') #define Tp template<typename T> #define Ts template<typename T,typename... Ar> using namespace std; Tp void read(T &x){ int f=1;x=0;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} x*=f; } namespace Debug{ Tp void _debug(char* f,T t){cerr<<f<<'='<<t<<endl;} Ts void _debug(char* f,T x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);} #define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__) }using namespace Debug; #define fi first #define se second #define mk make_pair int mod,n,m,K,s; int vis[maxn][maxn],f[maxn][maxn][maxn],g[maxn][maxn][maxn],ans; void add(int &x,int y) {x=(x+y)%mod;} signed main(void){ int i,j,k,t,x,y; read(n);read(m);read(K);read(mod);read(s); for (i=1;i<=n;i++) for (j=1;j<=m;j++) vis[i][j]=1; while (s--) { read(x);read(y); vis[x][y]=0; } if (vis[n][m]) g[n][m][0]=1; for (i=n;i>=1;i--) { for (j=m;j>=1;j--) if (vis[i][j]) { f[i][j][0]=1; for (k=1;k<=K;k++) for (t=0;t<k;t++) add(f[i][j][k],f[i][j][t]*(f[i+1][j][k-t-1]+f[i][j+1][k-t-1])); for (k=0;k<=K;k++) { for (t=0;t<=k;t++) add(g[i][j][k],f[i][j][t]*(g[i+1][j][k-t]+g[i][j+1][k-t])); } } } for (i=0;i<=K;i++) add(ans,g[1][1][i]); printf("%lld\n",ans); return 0; }
|