P1373 小a和uim之大逃离 - DP - 同余

49 篇文章 0 订阅
18 篇文章 0 订阅

得有从题意中抽象出模型的能力
抽象出数学表达,题意求的是使 k1k2mod(k+1) k 1 ≡ k 2 mod ( k + 1 ) 成立的方案数
注意模数是k+1啊,都说了k+1时算作0,k+2时算作1了
其实是数学题。。。
那么 k1k2mod(k+1) k 1 ≡ k 2 mod ( k + 1 ) 其实是比较难求的,除非记录状态,那就要多开一维,思考一下,同余还是可以移项的,现在就是求 k1k20mod(k+1) k 1 − k 2 ≡ 0 mod ( k + 1 )
(求解转判定)
因为要交替走,如果说按照一次走两步的走法是不行的,因为你不知道上一个状态是谁走到了,等等。。。我记下来不就好了吗
对于前后两次转移有限制的,需要知道上一次是什么的或是交替走的,一般都是设0/1表示是谁到了这个点,简单来说就是 目前不同的人、不同的情况、不同的决策 导致转移会不一样的时候(比如说换教室)
那么设出状态 f[i][j][k][0/1] 表示是小a/uim到(i,j)时,小a比uim多的魔液(模意义下的)为k的方案数
不能设他们的差是k,因为你不知道谁比谁大,实际上这种状态仍然十分模糊,而这个问题不能忽视这种模糊,就要把状态定的再精确一点,再复杂一点,再“不需要讨论”一点
显然转移是f[i][j][k][0] = f[i-1][j][( k-a[i][j] + (k+1) ) % (k+1)][1] + f[i][j-1][ ( k-a[i][j] + (k+1) ) % (k+1) ][1]
f[i][j][k][1] = f[i-1][j][( k+a[i][j] + (k+1) ) % (k+1)][0] + f[i][j-1][ ( k+a[i][j] + (k+1) ) % (k+1) ][0]
写转移的时候要慢,这个地方容易错
比如第二个方程,因为是减少了a[i][j],所以应该从更大的k转移而来
因为是求同余0,所以负下标的问题就一举解决了
另外注意longlong开不下 可以每次计算时都强转,这样循环结束一层后会释放内存,用时间换空间

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl; 
const int MAXN = 1010;
const int MOD = 1000000000 + 7;
int a[MAXN][MAXN],n,m,kk;
int ans, f[801][801][16][2];
int main() {
    scanf("%d %d %d", &n, &m, &kk);
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            scanf("%d", &a[i][j]);
        }
    }
    int mk = kk+1;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            f[i][j][a[i][j]][0] = 1;
            for(int k=0; k<=kk; k++) {
                f[i][j][k][0] += ( (long long)f[i-1][j][( k-a[i][j] + mk ) % mk][1] + f[i][j-1][( k-a[i][j] + mk ) % mk][1] ) % MOD;
                f[i][j][k][1] += ( (long long)f[i-1][j][( k+a[i][j] + mk ) % mk][0] + f[i][j-1][( k+a[i][j] + mk ) % mk][0] ) % MOD;
            }
            ans = ((long long)ans + f[i][j][0][1]) % MOD;
        }
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值