洛谷P1373 小a和uim之大逃离 动态规划

本文介绍了一种通过状态压缩优化动态规划算法的方法,用于解决两个角色魔力值相等的方案计数问题。通过减少状态数量,避免了内存和时间上的资源浪费。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解

我们可以先简单的想一种状态,也就是dp[i][j][x][y][t]dp[i][j][x][y][t]dp[i][j][x][y][t],这是最暴力的。
t=0t = 0t=0时,表示小a处于(i,j)(i,j)(i,j)位置,其中小a拥有x魔液,uim拥有y的魔液时候的方案总数。t=1t = 1t=1的时候反过来,意义类似。
这样的话我们很容里列出转移方程(这里就不给出了),但是这样的话内存和时间上都会爆炸800∗800∗15∗15∗2=288000000800*800*15*15*2=28800000080080015152=288000000,因此我们必须对状态进行压缩。
从要求出发,题目中要求两者魔力相等的方案数,也就是差值为000的方案数。
我们定义 dp[i][j][x][t]dp[i][j][x][t]dp[i][j][x][t]。当t = 0时候,表示小a位于(i,j)位置,且小a的魔力与uim的魔力相差为x的方案数。
容易列出状态转移方程:
dp[i][j][x][t]=dp[i][j−1][p][1−t]+dp[i−1][j][p][1−t]dp[i][j][x][t] = dp[i][j-1][p][1-t]+dp[i-1][j][p][1-t]dp[i][j][x][t]=dp[i][j1][p][1t]+dp[i1][j][p][1t]
其中p=(mat[i][j]−t+k)%kp = (mat[i][j]-t+k)\%kp=(mat[i][j]t+k)%k
推导过程:
sumt+mat[i][j]−sum1−t=xsum_t + mat[i][j] - sum_{1-t} = xsumt+mat[i][j]sum1t=x
p=sum1−t−sumt=mat[i][j]−x=(mat[i][j]−x+k)%kp = sum_{1-t}-sum_t = mat[i][j] - x = (mat[i][j]-x+k)\%kp=sum1tsumt=mat[i][j]x=(mat[i][j]x+k)%k

额外条件要注意!
由于只能从小a开始,因此初始化只初始化t=0t = 0t=0的情况
由于只能从uim结束,因此答案只加dp[i][j][0][1]dp[i][j][0][1]dp[i][j][0][1]


代码
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,k;
int dp[801][801][20][2];
const int mod = 1e9+7;
int mat[801][801];
int main(){
    scanf("%d%d%d",&n,&m,&k);
    ++k;
    for(int i = 1;i <= n;++i){
        for(int j = 1;j <= m;++j){
            scanf("%d",&mat[i][j]);
            dp[i][j][mat[i][j]%k][0] = 1;
        }
    }
    long long ans = 0;
    for(int i = 1;i <= n;++i){
        for(int j = 1;j <= m;++j){
            for(int t = 0;t < k;++t){
                int p = (mat[i][j]-t+k)%k;
                dp[i][j][t][0] += (dp[i-1][j][p][1]+dp[i][j-1][p][1])%mod;
                //p = (mat[i][j]+t)%k;
                dp[i][j][t][1] += (dp[i-1][j][p][0]+dp[i][j-1][p][0])%mod;
                dp[i][j][t][0] %= mod;
                dp[i][j][t][1] %= mod;
                //printf("i:%d,j:%d,t:%d,val:%d\n",i,j,t,dp[i][j][t][1]);
            }
            ans = (ans + dp[i][j][0][1])%mod;
        }
    }
    cout<<ans<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值