DP练习题

news2024/12/22 22:40:22

1.减操作(ACWING)

                          若有  a  b  c  d   e  f  g     几个数,

先对位置d操作   变成 a  b  c  d - e   f  g

再对c操作          变成 a  b  c - (d-e)  f  g

仔细分析后得出结论:对于第一个数如a, 它一定为正数,第二个数b,一定为负数,而其他数一定可以通过一些操作被加或者被减, 将题意转化为了改变某个数(>2)的正负性得到 t 

 dp[ i ][ j ]表示前i个数的和为 j 的第 i 个数之前的符号

 核心DP代码

f[1][a[1] + base] = 1;//防止负下标
    f[2][a[1] - a[2] + base] = -1;
for(int i = 3; i <= n; i ++)
{
    for(int j = -10000 + base; j <= 10000 + base; j ++)
    {
        if(f[i - 1][j] != 0) 
        {
            f[i][j + a[i]] = 1;
            f[i][j - a[i]] = -1;
        }
    }
}

另进行操作的位置一定是符号为正的位置 

2.旅行(ACWING)

 最长公共子序列 + 输出所有方案

用DFS来输出所有方案,加一个剪枝

f [ i ][ j ] 表示 a 串的前 i 个字母 和 b 串的前 j 个字母的最大相同长度

fa[ i ][ j ] 表示 a 串的前 i 个字符中字母 j + 'a' 出现的最后位置

fb[ i ][ j ] 表示 b 串的前 i 个字符中字母 j + 'a' 出现的最后位置

在找方案的时候,递归下标和长度去找,如在找 a 串前 la 个字符中和 b 串前 lb 个字符有 k 个相同的方案的时候,枚举第 k 个相同的为哪个字母,设为字母 c,那么对于a来说, 选择la之前的靠近la的 c 显然最好,b同理,这刚好是处理的 fa 和 fb 数组

核心DFS代码,因为最长公共子序列就是那个模板

void dfs(int x, int y, int k)
{
    if (k == 0) 
    { 
        ed.pb(string(ans + 1)); 
        return; 
    }
    for (int i = 0; i < 26; ++i)
    {
        int a = fa[x][i], b = fb[y][i];
        if (f[a][b] != k)
            continue;
        ans[k] = 'a' + i;
        dfs(a - 1, b - 1, k - 1);
    }
}

自己想想不到用DFS,因为感觉复杂度太大,但没想到还挺快

可能那个剪枝优化了很多状态吧

3.花匠(牛客)

f[ i ][ 0 / 1] 表示到以第 i 个位置结尾是上升 / 下降的最大长度

考虑状态如何转移

对于下降的来说,如果当前点小于上一个点, 即 i - 1 到 i 是下降的,那么需要 i - 2 到 i - 1 是上升的, 否则下降的不能选这个点结尾

if(a[i] < a[i - 1])
    f[i][1] = f[i - 1][0] + 1;
else 
    f[i][1] = f[i - 1][1];

对于上升 的来说,如果当前点大于上一个点, 即 i - 1 到 i 是上升的,那么需要 i - 2 到 i - 1 是下降的, 否则上升的不能选这个点结尾 

if(a[i] > a[i - 1])
    f[i][0] = f[i - 1][1] + 1;
else 
    f[i][0] = f[i - 1][0];

4.愤怒(牛客)

f [ i ][ j ] 表示第一个序列的左括号比右括号多 j 个的合法方案

当读到一个符号,可以选择把它放在第一个还是第二个中 

如果是左括号,状态dp[ i ] [ 0 ]只能给第二个序列

而dp [ i ][ j ]可以给第二个序列或者自己留下

if(s[i] == '(')
{
	top ++;
    dp[i][0] = dp[i - 1][0];//把(直接给了第二个序列
	for(int j = 1; j <= top; j ++)
	    dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % 2333;//给了+自己要
}
else
{
	top --;
	for(int j = top; j >= 0; j --)
	    dp[i][j] = (dp[i - 1][j] + dp[i - 1][j + 1]) % 2333;//给了+自己要
}

5.psd面试(牛客)

最长回文子序列

dp[ i ][ j ] 表示 i --- j 这段内的最长回文子串

int n = s.length();
for(int i = n - 1; i >= 0; i --)//枚举起点
{
    for(int j = 1; j + i < n; j ++)//枚举区间长度
    {
         if(s[i] == s[j + i])
              dp[i][j + i] = dp[i + 1][j + i - 1] + 2;
         else
              dp[i][j + i] = max(dp[i + 1][j + i], dp[i][j + i - 1]);
    }
}

6.找硬币

这道题为什么这么抽象啊

用dp[ i ]表示用最大面额为 i 的凑出答案的最小硬币数

初始化:dp[ 1 ] 表示用 1 来凑出每个物品, 那么初始答案就是所有的物品花费累加和

如果用 2 的纸币需要 10 个,那么用面额为 4 的 需要五个,所以可以用大面额的去更新减少小面额需要的

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

int n, maxn, ans = 10000000, a[55], dp[100010];
int main()
{
    memset(dp, 0x3f, sizeof(dp));
    dp[1] = 0;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        maxn = max(maxn, a[i]);
        dp[1] += a[i];//全部1
    }
    ans = dp[1];//用1购买全部
    for(int i = 1; i <= maxn; i ++)//用i来更新其他
    {
        for(int j = 2; j * i <= maxn; j ++)//枚举i的倍数
        {
            int chge = 0;//能用多少个大面额换
            for(int r = 1; r <= n; r ++)
                chge += a[r] / (i * j);
            //每个节省j - 1张
            //原先需要dp[i]个, 换成i * j的可以少(j - 1) * chge个
            dp[i * j] = min(dp[i * j], dp[i] - (j - 1) * chge);
            ans = min(ans, dp[i * j]);
        }
    }
    
    printf("%d\n", ans);
}

7.月之谜(acwing)

感觉数位DP实在克我,对大佬代码进行注释

AcWing 311. 月之谜 - AcWing

/*一个数的余数等于这个数的拆分的余数之和取余*/
/*如 5632 % p = (5000 % p + 600 % p + 30 % p + 2 % p) % p*/
/*所以在下面枚举的时候, 可以记录当前i位对p取余的余数,这样不影响正确性*/
#include <iostream>
#include<cstring>
#define int long long 

using namespace std;

const int maxn = 100;

int f[30][maxn][maxn], num[maxn], p;
//f[i][j][k]表示前i个数,当前数位和为sum,且当前余数是k的方案数

int dfs(int u, int sum, int mod, bool limit)//pos为当前数位,sum为当前数位之和(p为枚举的数位之和),mod为当前余数,limit为上一位是否达到上限的标志
{
    if(!u)//已经到了最后一位
    {
        if(sum == p && !mod)  return 1;//如果枚举到了一个存在的数,且是月之数
        return 0;
    }
    if(!limit && f[u][sum][mod] != -1) //当前数不超限且之前被计算过
        return f[u][sum][mod];
        
    int res = 0, up = limit ? num[u] : 9;//若上一位达到限制,当前位也有限制,否则 0 ~ 9 都可以填
    for(int i = 0; i <= up; i ++)//枚举当前位填什么
    {
        //如果前几位都取到上限后一位必须取上限
        res += dfs(u - 1, sum + i, (mod * 10 + i) % p, limit && i == up);
    }
    return limit ? res : f[u][sum][mod] = res;
}

int solve(int n)//计算1-n中满足条件的数(月之数)的个数
{
    int cnt = 0;
    while(n)
    {
        num[++ cnt] = n % 10;//每位数的上限
        n /= 10;
    }
    int res = 0;
    for(p = 1; p < maxn; p ++)//枚举所有可能数位之和 10 * 9 = 90
    {
        memset(f, -1,sizeof f);
        res += dfs(cnt, 0, 0, 1);
    }
    return res;
}

signed main()
{
    int l,r;
    cin >> l >> r;
    cout << solve(r) - solve(l - 1) << endl;
    return 0;
}

8.打鼹鼠(牛客)

用f[ i ] 表示从前 i 个鼹鼠中选的最大数列

能够转移等价于两个鼹鼠之间的距离 <= 后一个鼹鼠出现的时间 - 前一个鼹鼠出现的时间

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;
int f[N], n, m;
struct node
{
	int t, x, y;
}mi[N];

bool check(int a, int b)
{
	int t = mi[a].t - mi[b].t;
	int w = abs(mi[a].x - mi[b].x) + abs(mi[a].y - mi[b].y);
	return t >= w;
}
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= m; i ++)
	{
		int t, x, y;
		scanf("%d%d%d", &t, &x, &y);
        mi[i] = {t, x, y};
		f[i] = 1;
		for(int j = 1; j < i; j ++)
			if(check(i, j)) f[i] = max(f[i], f[j] + 1);
	}
	int res = 0;
	for(int i = 1; i <= m; i ++) res = max(res, f[i]);
	cout << res << endl;
	return 0;
} 

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/493448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java并发(四)----线程运行原理

1、线程运行原理 1.1 栈与栈帧   Java Virtual Machine Stacks &#xff08;Java 虚拟机栈 JVM&#xff09; 我们都知道 JVM 中由堆、栈、方法区所组成&#xff0c;其中栈内存是给谁用的呢&#xff1f;其实就是线程&#xff0c;每个线程启动后&#xff0c;虚拟机就会为其分…

java 解密springboot的WEB端口是谁启动的之内嵌tomcat

找到项目的 pom.xml 看到下面的spring-boot-starter-web 我们按住 Ctrl 点击进去 里面就有一个 tomcat 简单说 我们的程序能启动起tomcat端口 就是靠的这个东西 简单说 就是在程序中嵌了一个tomcat服务器 这里 可能就有小伙伴蒙了 不是把程序放在服务器上运行吗&#xff1f…

Linux Driver 和Device匹配过程分析(2)

Linux Driver 和Device匹配过程分析&#xff08;2&#xff09; 1 device注册流程2&#xff0c;driver注册匹配过程&#xff1a;2.1 pci_register_driver2.1.1 nvme_init2.1.2 pci_register_driver2.1.3 __pci_register_driver2.1.4 driver_register2.1.5 bus_add_driver2.1.6 d…

读书笔记——《2001太空漫游》

阿瑟克拉克神作&#xff0c;任何一个科幻迷都绕不开的一部作品。很早就听说过其大名&#xff0c;因为之前看过电影版的&#xff0c;总感觉少了点新鲜感&#xff0c;这本书就一直在书架上没有拿出来看。但是看过这本书后&#xff0c;我可以很负责任的说&#xff0c;全书都充满新…

【递推专题】常见的递推“模型”总结

目录 1.斐波那契数列分析&#xff1a;代码&#xff1a; 2.平面分割问题分析&#xff1a; 3.汉诺塔问题分析&#xff1a; 4.卡特兰数分析&#xff1a; 5.第二类斯特林数总结&#xff1a; 1.斐波那契数列 分析&#xff1a; 斐波那契数列又称兔子数列&#xff0c;其原理来源于兔子…

dangerousRemoteUrlIpcAccess

问题描述&#xff1a; 在使用Tauri窗口加载外部链接时&#xff0c;需要也能继续使用Tauri API与Rust交互。按照官方发布通告中的代码添加配置&#xff1a; "security": {"dangerousRemoteUrlIpcAccess": [ { "windows": ["main", &qu…

在Linux中进行Jenkins部署(maven-3.9.1+jdk8)

Jenkins部署在公网IP为x.x.x.x的服务器上 maven-3.9.1要安装在jdk8环境中 环境准备 第一步&#xff0c;下载server-jre-8u202-linux-x64.tar.gz安装包。 登录地址&#xff1a;https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html下载server-j…

Maven命令和配置详解

Maven命令和配置详解 1. pom基本结构2. build基本结构3. Maven命令详解3.1 打包命令3.2 常用命令3.3 批量修改版本-父子pom4. Maven配置详解4.1 settings.xml4.2 项目内的maven工程结构Maven POM构建生命周期工程实践1. pom基本结构 <?xml versi

《程序员面试金典(第6版)》面试题 16.13. 平分正方形(直线的斜截式方程,C++)

题目描述 给定两个正方形及一个二维平面。请找出将这两个正方形分割成两半的一条直线。假设正方形顶边和底边与 x 轴平行。 每个正方形的数据square包含3个数值&#xff0c;正方形的左下顶点坐标[X,Y] [square[0],square[1]]&#xff0c;以及正方形的边长square[2]。所求直线穿…

JDK8 中Arrays.sort() 排序方法解读

一、引言 在刷算法的时候经常需要对数组进行排序&#xff0c;第一反应就是直接使用java.util包下的Arrays.sort()方法直接排序。但在刷算法时会通过时间复杂度和空间复杂度对实现的算法进行评价&#xff0c;因此我们需对Arrays.sort()方法有所了解。 本文先行介绍Arrays.sort…

图的基本概念和术语

图&#xff1a;G&#xff08;V,E&#xff09; V:顶点&#xff08;数据元素&#xff09;的又穷非空集合&#xff1b; E:边的有穷集合。 无向图&#xff1a;每条边都是无方向的G2 有向图&#xff1a; 每条边都是有方向的G1 完全图&#xff1a;任意两个点都有一条边相连 假设…

使用rollup打包ts+react缓存组件发布npm

新建一个项目目录比如叫root,下面新建一个rollup的配置文件: rollup.config.ts 因为rollup良好支持ts和esmodule 所以用ts配置文件 Setup 生成一个package.json文件,这里用pnpm生成: pnpm init安装rollup和Typescript: pnpm add rollup pnpm add typescript配置package.jso…

Android 自定义View 之 简易输入框

简易输入框 前言正文① 构造方法② XML样式③ 测量④ 绘制1. 绘制方框2. 绘制文字 ⑤ 输入1. 键盘布局2. 键盘接口3. 键盘弹窗4. 显示键盘5. 相关API 四、使用自定义View五、源码 前言 在日常工作开发中&#xff0c;我们时长会遇到各种各样的需求&#xff0c;不部分需求是可以通…

在云服务器上部署jupyter服务

1.准备一台云服务器&#xff0c;阿里云、腾讯云都可以&#xff0c;并且远程登陆&#xff0c;在云服务器的安全组中配置8888的访问端口&#xff0c;因为jupyter默认的访问端口是8888&#xff0c;如下述步骤&#xff1b;以阿里云服务器的centos系统为例 2.使用以下命令在服务器…

golang 微服务容错处理是如何做的?

随着微服务的规模越来越大&#xff0c;各个微服务之间可能会存在错综复杂的调用关系 在我们实际工作中&#xff0c;确实慢慢的也出现了很多问题&#xff0c;整个系统的弊端的慢慢的展现出来 例如就会有这样的情况&#xff1a; 服务 A 去请求服务B&#xff0c;服务 B 还需要去…

HTB-Silo

HTB-Silo 信息收集立足root哈希传递攻击 信息收集 分别对smb和rpc都进行guest用户和空密码测试。 1521的Oracle TNS listener 11.2.0.2.0。 搜索可能存在的漏洞。 得到一个CVE编号cve-2012-1675。同时我们可以对其进行SID枚举&#xff0c;SID说简单点就是数据库的名字。 简单…

错题汇总04

1.以下C语言指令&#xff1a; int a[5] {1,3,5,7,9}; int *p (int *)(&a1); printf(“%d,%d”,*(a1)&#xff0c;*(p-1)); 运行结果是什么&#xff1f; A 2,1 B 3,1 C 3,9 D 运行时崩溃 数组名只有在&与sizeof之后&#xff0c;才表明数组本身&#xff0c;其余表…

平均情况时间复杂度

// n表示数组array的长度 int find(int[] array, int n, int x) {int i 0;int pos -1;for (; i < n; i) {if (array[i] x){ pos i; break;}}return pos; } 通过以上代码&#xff0c;我们分析一下平均情况时间复杂度。 以上代码要查找的变量 x 在数组中的位置&#xff…

并发编程02:CompletableFuture

文章目录 2.1 Future接口理论知识2.2 Future接口常用实现类FutureTask异步任务2.2.1 Future接口能干什么2.2.2 Future接口相关架构2.2.3 Future编码实战和优缺点分析2.2.4 完成一些复杂的任务 2.3 CompletableFuture对Future的改进2.3.1 CompletableFuture为什么会出现2.3.2 Co…

Redis持久化篇

文章目录 持久化篇1、AOF持久化是怎么实现的&#xff1f;1.1、AOF日志1.2、三种写回策略1.3、AOF重写机制1.4、AOF后台重写 2、RDB快照是怎么实现的&#xff1f;2.1、快照怎么使用2.2、执行快照时&#xff0c;数据能被修改吗&#xff1f;2.3、RDB和AOF合体 3、Redis大key对持久…