洛谷P1373 小a和uim之大逃离【DP】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/82793526

时空限制 1000ms / 128MB

题目描述

瞬间,地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液。怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束。开始时小a用魔瓶吸收地面上的魔液,下一步由uim吸收,如此交替下去,并且要求最后一步必须由uim吸收。魔瓶只有k的容量,也就是说,如果装了k+1那么魔瓶会被清空成零,如果装了k+2就只剩下1,依次类推。怪物还说道,最后谁的魔瓶装的魔液多,谁就能活下来。小a和uim感情深厚,情同手足,怎能忍心让小伙伴离自己而去呢?沉默片刻,小a灵机一动,如果他俩的魔瓶中魔液一样多,不就都能活下来了吗?小a和他的小伙伴都笑呆了!

现在他想知道他们都能活下来有多少种方法。

输入格式:

第一行,三个空格隔开的整数n,m,k
接下来n行,m列,表示矩阵每一个的魔液量。同一行的数字用空格隔开。

输出格式:

一个整数,表示方法数。由于可能很大,输出对1 000 000 007取余后的结果。

【数据范围】

对于20%的数据,n,m<=10,k<=2
对于50%的数据,n,m<=100,k<=5
对于100%的数据,n,m<=800,1<=k<=15


题目分析

d p [ i ] [ j ] [ k ] [ 0 / 1 ] dp[i][j][k][0/1] 表示走到 ( i , j ) (i,j) 时两人魔液的差(小A-小uim)为k
且当前为小A(0)/小uim(1)取的方案数

转移方程为

dp[i][j][l][0]=(dp[i][j][l][0]+dp[i-1][j][(l-a[i][j]+k)%k][1])%mod//当前小A取,差值增大
dp[i][j][l][0]=(dp[i][j][l][0]+dp[i][j-1][(l-a[i][j]+k)%k][1])%mod//所以转移时为l-a[i][j]
dp[i][j][l][1]=(dp[i][j][l][1]+dp[i-1][j][(l+a[i][j])%k][0])%mod//当前小uim取,差值减小转移时
dp[i][j][l][1]=(dp[i][j][l][1]+dp[i][j-1][(l+a[i][j])%k][0])%mod//所以转移时为l+a[i][j]

初始化为 d p [ i ] [ j ] [   a [ i ] [ j ]   ] [ 0 ] = 1 dp[i][j][\ a[i][j]\ ][0]=1
最后 a n s = i = 1 n j = 1 m d p [ i ] [ j ] [ 0 ] [ 1 ] ans=\sum_{i=1}^n\sum_{j=1}^mdp[i][j][0][1]

注意模数应该是k+1


#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int mod=1000000007;
const int maxn=805;
int n,m,k;lt ans;
int a[maxn][maxn],dp[maxn][maxn][17][2];

int main()
{
    n=read();m=read();k=read()+1;
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    a[i][j]=read()%k,dp[i][j][a[i][j]%k][0]=1;
    
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    for(int l=0;l<k;++l)
    dp[i][j][l][0]=(dp[i][j][l][0]+dp[i-1][j][(l-a[i][j]+k)%k][1])%mod,
    dp[i][j][l][0]=(dp[i][j][l][0]+dp[i][j-1][(l-a[i][j]+k)%k][1])%mod,
    dp[i][j][l][1]=(dp[i][j][l][1]+dp[i-1][j][(l+a[i][j])%k][0])%mod,
    dp[i][j][l][1]=(dp[i][j][l][1]+dp[i][j-1][(l+a[i][j])%k][0])%mod;
    
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    ans=(ans+dp[i][j][0][1])%mod;
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/82793526