[luogu]P1373 小a和uim之大逃离

本文介绍了一个关于矩阵中路径计数的问题。从任意起点到任意终点,仅能向下或向右移动,且移动步数必须为偶数。文章通过动态规划的方法解决此问题,并给出了一段C++代码实现。

题目

给定n\times m矩阵,矩阵每个元素有一个p\in[0,k]的值,可以从任意点出发并在任意点停止,但只能向下或向右走。走必须为偶数步,每一步会得到一个权值p_{ij},求方案数,满足\sum_{2|i}p_{i}\equiv \sum_{2\nmid i}p_{i} (mod\ k+1),p_{i}为每一步的权值。

数据范围: 1 \leq n,m \leq 800,\ 1\leq k \leq 15

dp策略

先令dp[i][j][]为终点在(i,j)的符合条件的方案数([]中为其他刻画状态条件),可以看出,其主要依赖于(i-1,j),(i,j-1)两项(考虑奇偶步),或依赖于(i-2,j),(i-1,j-1),(i,j-2)三项(不考虑奇偶步).

由于求和涉及mod,故先考虑dp[i][j][]=>dp[i][j][k][k^{'}],表示终点在(i,j),\sum_{2|i}p_{i}\equiv k (mod\ k+1),\ \sum_{2\nmid i}p_{i}\equiv k^{'}(mod\ k+1)的方案数(不考虑奇偶步),ans=\sum_{1\leq i \leq n,1 \leq j \leq m,0 \leq l \leq k} dp[i][j][l][l].

dp[i][j][k][k^{'}]依赖于(i-2,j),(i-1,j-1),(i,j-2)三项,但这样做时间空间都会炸掉ε=ε=ε=ε=ε=ε=┌(; ̄◇ ̄)┘

考虑\sum_{2|i}p_{i}\equiv \sum_{2\nmid i}p_{i} (mod\ k+1),进行变形\sum p_{i} * (-1)^{i+1} \equiv 0 (mod\ k+1)dp[i][j][]=>dp[i][j][\Delta k][parity],  \Delta k刻画差值,parity刻画步数(奇数为0,偶数为1),.ans = \sum_{1\leq i \leq n, 1 \leq j \leq m, 0 \leq \delta k \leq k}dp[i][j][\delta k][1].

dp[i][j][\Delta k][parity]依赖于(i-1,j),(i,j-1)两项,空间与时间都是O(n*m*k)

初始化: dp[i][j][p_{ij} \% (k+1)][0]=1 (1 \leq i \leq n, 1 \leq j \leq m),其余为0

转移方程: \\ dp[i][j][(l+p_{ij})\%(k+1)][0]\ +=dp[i-1][j][l][1]+dp[i][j-1][l][1]\\ dp[i][j][(l-p_{ij})\%(k+1)][1]\ +=dp[i-1][j][l][0]+dp[i][j-1][l][0]\\ (1 \leq i \leq n, 1 \leq j \leq m, 0 \leq l \leq k)

ps: dp数组开int,不然莫名MLE

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

using LL = long long;
const int MOD = 1e9 + 7;
int N, M, K;
int p[805][805];
int dp[805][805][18][2];
LL ans;

int main(){
  ios::sync_with_stdio(false);
  int i, j, l;
  cin >> N >> M >> K, K++;
  for(i = 1; i <= N; i++)
    for(j = 1; j <= M; j++)
      cin >> p[i][j];

  for(i = 1; i <= N; i++)
    for(j = 1; j <= M; j++)
      dp[i][j][p[i][j] % K][0]++;
  for(i = 1; i <= N; i++)
    for(j = 1; j <= M; j++){
      for(l = 0; l < K; l++){
        dp[i][j][(l + p[i][j]) % K][0] += dp[i - 1][j][l][1] + dp[i][j - 1][l][1];
        dp[i][j][(l + p[i][j]) % K][0] %= MOD;
        dp[i][j][(l - p[i][j] + K) % K][1] += dp[i - 1][j][l][0] + dp[i][j - 1][l][0];
        dp[i][j][(l - p[i][j] + K) % K][1] %= MOD;
      }
      ans = (ans + dp[i][j][0][1]) % MOD;
    }
  cout << ans << endl;
  return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值