首页 > 其他分享 >二维dp

二维dp

时间:2024-07-06 13:52:34浏览次数:11  
标签:百合花 硬币 int ++ 二维 static dp

阿里巴巴2023092501

题目描述

在一个 ( n × n ) 的正方形训练场上,每个位置都有一枚硬币。小明从左上角 (0, 0) 出发,跳跃可以按以下方式进行:

  1. 向右走一步,再向上或向下走两步。
  2. 向右走两步,再向上或向下走一步。

小明不能跳出训练场,也不能往回跳。目标是帮助小明获得尽可能多的硬币。

输入描述

  • 第一行输入一个整数 n ( 3 ≤ n ≤ 1000 ),表示训练场的大小。
  • 接下来 n 行,每行输入 n 个整数表示每个位置的硬币数量 ( aij ) ( 1 ≤ ( aij ) ≤ 10⁹ )。

输出描述

  • 输出一个整数表示小明可以获得的最多硬币数量。

样例

输入:

3
1 1 4
5 1 4
1 9 19

输出:

14

限制:
1秒,1024KiB 内存。

思路

二维dp

1、枚举方向数组 :
dx = {1, 1, 2, 2} (向右走一步或两步)
dy = {-2, 2, -1, 1} (向上或向下走两步或一步)

2、状态方程
dp[i][j] : 跳跃到(i,j) 小明可以获得的最多硬币数量为dp[i][j]。
dp[i][j] = max(dp[i+dxi][j+dxi],dp[i][j])
3、初始化
因为dp更新方向始终向右,所以只需要初始化最左边起点,
dp[0][0] = map[0][0]
因为 0 ≤ 1 ≤ ( aij ) , 其余默认初始化为0就可以了

import java.io.*;
import java.util.*;

public class Main {
    static int[][] map;
    static long[][] dp;

    static int[] dy = {-2, 2, -1, 1};
    static int[] dx = {1, 1, 2, 2};

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        map = new int[n][n];
        for (int i = 0; i < n; i++) {
            String[] split = reader.readLine().split(" ");
            for (int j = 0; j < n; j++) {
                map[i][j] = Integer.parseInt(split[j]);
            }
        }
        dp = new long[n][n];
        for (long[] p : dp) Arrays.fill(p, Long.MIN_VALUE / 2);
        dp[0][0] = map[0][0];
        //外层循环应从 j = 1 开始,这样每次只会考虑向右的移动。
        for (int j = 1; j < n; j++) {
            for (int i = 0; i < n; i++) {
                for (int d = 0; d < 4; d++) {
                    int nx = i - dy[d];
                    int ny = j - dx[d];
                    if (nx < 0 || nx >= n || ny < 0 || ny >= n) {
                        continue;
                    }
                    dp[i][j] = Math.max(dp[i][j], dp[nx][ny] + map[i][j]);
                }
            }
        }
        
        long res = 0L;
        for (int i = 0; i < n; i++) {
            res = Math.max(res, dp[i][n - 1]);
        }
        System.out.println(res);
    }
}

4741魔法百合井

森林里有一口魔法井,井中有 ( L ) 朵百合花。

你可以向井里投入硬币来获取百合花:

  1. 投入 1 个硬币,可以得到 1 朵百合花。
  2. 投入 4 个硬币,记录当前篮子里的百合花数量。
  3. 投入 2 个硬币,得到上次记录数量的百合花。

如果井中百合花数量不足,投入 1 个或 2 个硬币不会有任何效果。

请计算为了获取所有百合花,所需的最少硬币数量。

输入格式

  • 第一行包含整数 ( T ),表示测试数据的组数。
  • 接下来 ( T ) 行,每行包含一个整数 ( L ),表示井中百合花的数量。

输出格式

  • 对于每组数据,输出结果格式为 Case #x: y,其中 ( x ) 为组别编号(从 1 开始),( y ) 为需要的最少硬币数量。

数据范围

  • ( 1 ≤ T ≤ 100 )
  • ( 1 ≤ L ≤ 10^5 )

输入样例

2
5
20

输出样例

Case #1: 5
Case #2: 15

样例解释

  • Case 1: 投入 5 次 1 个硬币,共 5 个硬币。
  • Case 2: 投入 5 次 1 个硬币,再投入 4 个硬币记录,然后 3 次 2 个硬币,共 15 个硬币。

思路

f[i] : 表示获得i朵百合花的最少硬币数量

状态转移方程简化

操作1

选择1可以得到状态转移方程:
f[i] = f[i-1] + 1

操作2

  1. 选择3累加上次记录的百合花。
  2. 要使用选择3,必须先使用选择2。
  3. 使用选择2后可以连续执行选择3。
  4. 设使用选择3的次数为 ( j ),选择3前的百合花数量为 ( i )。i,j∈[1,n]
  5. 使用 ( j ) 次选择3后的百合花总数为 ( (j+1) * i )。
  6. 花费的硬币数量为 ( 4 + 2 * j )。

所以状态转移方程为:

f(j+1) * i = min(f(j+1) * i, fi + 4 + 2 * j)

import java.util.*;
public class Main{
    static int N = (int)1e5 + 10;
    static int[] dp = new int[N];
    static {
        // dp[0] = 0 
        for (int i = 1; i < N; i++) dp[i] = 0x3f3f3f3f;
        for (int i = 1; i < N; i++) {
            dp[i] = Math.min(dp[i], dp[i - 1] + 1);
            for (int j = 1,  i * (j + 1); i * (j + 1) < N; j++) { 
                dp[i * (j + 1)] = Math.min(dp[i * (j + 1)], dp[i] + 4 + 2 * j);
            }
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        for (int i = 1, tol = sc.nextInt(); i <= tol; i++) {
            int n = sc.nextInt();
            System.out.println("Case #" + i +": " + dp[n]);
        }
    }
}

阿里巴巴淘天2023090202

定义一个“特别数组”,满足以下三个条件:

  1. 对于 1 ≤ i ≤ n,有 1 ≤ ai ≤ m
  2. 对于 1 ≤ i ≤ n,ai 是 i 的倍数。
  3. a1 + a2 + ... + an 是 n 的倍数。

给出 n 和 m,求满足条件的“特别数组”数量,对 10^9 + 7 取模。

输入描述:

两个正整数 n 和 m,用空格隔开。
1 ≤ n, m ≤ 1000

输出描述:

特别数组的数量,对 10^9 + 7 取模。

示例:

输入:

3 5

输出:

4

思路:

二维dp+枚举

f[i][j] : 前i个数的总和结果对n取模的结果为j的方案数.
1.对i个数进行枚举,1 ≤ i ≤ n;
2.对前i-1个数可能的总和(j)进行枚举,因为需要对n进行取模(j为n的倍数),所以j∈[0,n)(条件3);
3.对于第i个数ai(1 ≤ ai ≤ m),可能的值为i,2*i,...,n(条件2)
4.dp[i][(j+ai)%n] = (dp[i-1][j] + dp[i][(j+ai)%n])%(1e9+7)

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author 17259
 * @create 2024-06-18 10:32
 */
public class Main {
    static final int mod = (int) 1E9 + 7;

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] split = reader.readLine().split(" ");
        int n = Integer.parseInt(split[0]);
        int m = Integer.parseInt(split[1]);
        System.out.println(solve(n, m));
    }

    private static long solve(int n, int m) {
        long[][] dp = new long[n + 10][m + 10];
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            // j = dp[i-1][j] : 前i-1个数总和...
            for (int j = 0; j < n; j++) {
                for (int k = i; k <= m; k += i) {
                    dp[i][(j + k) % n] = (dp[i - 1][j] + dp[i][(j + k) % n]) % mod;
                }
            }
        }
        return dp[n][0];
    }
}

携程2023090704

给定一个只包含字符 '0' 和 '1' 的字符串,求该字符串中有多少个“好字串”。“好字串”的定义是其所有前缀中 '0' 的数量严格大于 '1' 的数量。

输入描述

一个只包含 '0' 和 '1' 的字符串,长度不超过 100000。

输出描述

一个整数,表示“好字串”的数量。

示例

输入

10

输出

1

说明

子区间 [2, 2] 组成的子串是一个好串。

输入

11010

输出

2
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        long res = 0;
        int cnt = 0;
        for(char ch : s.toCharArray()){
            if(ch == '0'){
                cnt++;
            }
            else{
                cnt = Math.max(cnt - 1, 0);
            }
            res += cnt;
        }
        System.out.println(res);
    }
}

标签:百合花,硬币,int,++,二维,static,dp
From: https://www.cnblogs.com/alohablogs/p/18251784

相关文章

  • 用免费WordPress和Cloudflare打造媲美收费服务的网站
    你是否曾因为网站搭建的高昂费用而犹豫不决?别担心,我来告诉你一个几乎零成本的解决方案,让你轻松拥有一个功能强大的网站。通过免费域名、免费PHP主机、WordPress程序和CloudflareCDN服务的组合,你可以打造出一个媲美收费服务的网站。首先,你需要一个域名。在lita.eu.org注册免费......
  • 可视化二维函数的拉普拉斯算子 - 使用有限差分法来近似计算二维标量函数的拉普拉斯算
    可视化二维函数的拉普拉斯算子-使用有限差分法来近似计算二维标量函数的拉普拉斯算子flyfish算子(Operator)是指的是一个将函数、向量或其他对象映射到另一对象的数学实体。简单来说,算子就是一种“操作”或“变换”,它把一个输入(通常是函数或向量)变换成另一个输出。算子可......
  • FreeRDP使用,快速找出账户密码不正确的服务器地址
    最近有个需求,需要找出服务器未统一设置账户密码的服务器,进行统一设置,一共有一百多台服务器,一个个远程登录看,那得都费劲啊,这时候就可以用到FreeRDP这个远程桌面协议工具,FreeRDP下载,根据自己的需要下载,我是windows1064位系统就下载了个wfreerdp,下载好了之后就可以写代码了......
  • 四种封装 ThreadPoolExecutor 的线程池的使用以及直接使用 ThreadPoolExecutor ,优缺点
    池化思想:线程池、字符串常量池、数据库连接池提高资源的利用率下面是手动创建线程和执行任务过程,可见挺麻烦的,而且线程利用率不高。手动创建线程对象执行任务执行完毕,释放线程对象线程池的优点:提高线程的利用率提高程序的响应速度便于统一管理线程对象可以控制最大并发......
  • Python多线程-线程池ThreadPoolExecutor
    1.线程池不是线程数量越多,程序的执行效率就越快。线程也是一个对象,是需要占用资源的,线程数量过多的话肯定会消耗过多的资源,同时线程间的上下文切换也是一笔不小的开销,所以有时候开辟过多的线程不但不会提高程序的执行效率,反而会适得其反使程序变慢,得不偿失。为了防止无尽的线程......
  • P8592 『JROI-8』颅脑损伤 2.0(加强版)(线性 dp + 单调队列优化)
    P8592『JROI-8』颅脑损伤2.0(加强版)线性dp+单调队列优化最优化问题,考虑dp。先离散化,按左端点排序,设\(f_i\)表示考虑完前\(i\)条线段符合条件的染色,最小长度和。转移枚举上一条红色线段\(j\),\(f_i=f_j+len_i\)。当然\(j\)需要满足题目的条件,即\((j,i)\)中的黑色线......
  • 从零开始使用WordPress搭建个人网站并一键发布公网详细教程
    文章目录前言1.搭建网站:安装WordPress2.搭建网站:创建WordPress数据库3.搭建网站:安装相对URL插件4.搭建网站:内网穿透发布网站4.1命令行方式:4.2.配置wordpress公网地址5.固定WordPress公网地址5.1.固定地址访问WordPress前言本文主要介绍如何在LinuxUbuntu......
  • LeetCode刷题之搜索二维矩阵
    20247/5一如既往的晴天,分享几张拍的照片嘿嘿,好几天没做题了,在徘徊、踌躇、踱步。蝉鸣的有些聒噪了,栀子花花苞也都掉落啦,今天给他剪了枝,接回一楼来了。ok,做题啦!图1、宿舍阳台摄,每天都是如此美景图2、吃饭路上桥上摄图3、桥的另一边摄okok,做题啦!1、题目描述2、算......
  • 小国王 骑士 状态压缩DP
    //小国王.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。//#include<iostream>#include<vector>usingnamespacestd;/*https://loj.ac/p/10170http://ybt.ssoier.cn:8088/problem_show.php?pid=1592在nxn的棋盘上放k个国王,国王可攻击相邻的......
  • 远程桌面协议(RDP)
    原文链接:https://zhuanlan.zhihu.com/p/679953523在信息化社会中,远程工作、协作和管理已成为常态。远程桌面协议(RemoteDesktopProtocol,简称RDP)作为一种关键技术,为用户提供了如同身临其境般的远程计算机操作体验。那么,究竟什么是RDP?它又如何赋能我们的日常工作与生活呢?揭开RDP......