zoukankan      html  css  js  c++  java
  • [dp]洛谷 P1373 小a和uim之大逃离

    题目背景

    小a和uim来到雨林中探险。突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声。刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个披头散发、青面獠牙的怪物,低沉着声音说:“呵呵,既然你们来到这,只能活下来一个!”。小a和他的小伙伴都惊呆了!

    题目描述

    瞬间,地面上出现了一个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取余后的结果。

    输入输出样例

    输入样例#1:
    2 2 3
    1 1
    1 1
    输出样例#1:
    4

    【数据范围】

    对于20%的数据,n,m<=10,k<=2

    对于50%的数据,n,m<=100,k<=5

    对于100%的数据,n,m<=800,1<=k<=15

    题解

    首先n和m都比较小,可以满足O(nmk)
    可以设f[i][j][p][0/1]为走到(i,j),两人的魔液差为p,0表示当前是小a在这里吸,1表示是uim在这里吸
    显然,状态转移方程为
    f[i][j][p][0]=(f[i][j][p][0]+f[i-1][j][((p-a[i][j])%k+k)%k][1]+f[i][j-1][((p-a[i][j])%k+k)%k][1])%mo
    f[i][j][p][1]=(f[i][j][p][1]+f[i-1][j][((p+a[i][j])%k+k)%k][l]+f[i][j-1][((p+a[i][j])%k+k)%k][l])%mo
    O(nmk)得出f数组
    O(nm)统计
    

    代码

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int mo=1000000007;
    int n,m,k,a[900][900],f[900][900][20][2];
    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",&a[i][j]);
                f[i][j][a[i][j]%k][0]++;
            }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                for (int z=0;z<k;z++)
                {
                    f[i][j][z][0]=(f[i][j][z][0]+f[i-1][j][((z-a[i][j])%k+k)%k][1]+f[i][j-1][((z-a[i][j])%k+k)%k][1])%mo;
                    f[i][j][z][1]=(f[i][j][z][1]+f[i-1][j][((z+a[i][j])%k+k)%k][0]+f[i][j-1][((z+a[i][j])%k+k)%k][0])%mo;
                }
        int ans=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                ans=(ans+f[i][j][0][1])%mo;
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    1093 Count PAT's(25 分)
    1089 Insert or Merge(25 分)
    1088 Rational Arithmetic(20 分)
    1081 Rational Sum(20 分)
    1069 The Black Hole of Numbers(20 分)
    1059 Prime Factors(25 分)
    1050 String Subtraction (20)
    根据生日计算员工年龄
    动态获取当前日期和时间
    对计数结果进行4舍5入
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412236.html
Copyright © 2011-2022 走看看