小a和uim之大逃离
很不错的一道DP题……
这个题的关键之处在于在两者之间收集的魔液的差值上进行DP(很像多米诺骨牌那道题),我们用dp[i][j][p][0/1]表示在点(i,j),当前两者魔液差值%(k+1)为p,0/1表示小a/uim正在取魔液的方案数,就有DP方程如下:
dp[i][j][h][0] += dp[i][j-1][(h - a[i][j] + k) % k][1],dp[i][j][h][0] %= mod; dp[i][j][h][0] += dp[i-1][j][(h - a[i][j] + k) % k][1],dp[i][j][h][0] %= mod; dp[i][j][h][1] += dp[i][j-1][(h + a[i][j]) % k][0],dp[i][j][h][1] %= mod; dp[i][j][h][1] += dp[i-1][j][(h + a[i][j]) % k][0],dp[i][j][h][1] %= mod;
这个DP的初始化是对于每一个a[i][j]不为0的点初始化为1,之后直接三重循环DP即可,最后答案枚举所有点累加。
看一下代码。
// luogu-judger-enable-o2 #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<ctime> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 1005; const int mod = 1e9 + 7; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } int n,m,k,dp[805][805][20][2],a[805][805]; ll ans; int main() { n = read(),m = read(),k = read() + 1; rep(i,1,n) rep(j,1,m) a[i][j] = read(),dp[i][j][a[i][j]%k][0] = 1; rep(i,1,n) rep(j,1,m) rep(h,0,k) { dp[i][j][h][0] += dp[i][j-1][(h - a[i][j] + k) % k][1],dp[i][j][h][0] %= mod; dp[i][j][h][0] += dp[i-1][j][(h - a[i][j] + k) % k][1],dp[i][j][h][0] %= mod; dp[i][j][h][1] += dp[i][j-1][(h + a[i][j]) % k][0],dp[i][j][h][1] %= mod; dp[i][j][h][1] += dp[i-1][j][(h + a[i][j]) % k][0],dp[i][j][h][1] %= mod; } rep(i,1,n) rep(j,1,m) ans += dp[i][j][0][1],ans %= mod; printf("%lld\n",ans); return 0; }
当你意识到,每个上一秒都成为永恒。