蓝桥杯AcWing学习笔记 9-2复杂DP的学习(下)

蓝桥杯

我的AcWing

题目及图片来自蓝桥杯C++ AB组辅导课

复杂DP(下)

非传统DP问题思考方式,全新的DP思考方式:从集合角度来分析DP问题——闫式DP分析法

例题

AcWing 1303. 斐波那契前 n 项和

矩阵乘法+快速幂

此题并非dp问题,是为了后面的蓝桥杯真题铺垫知识点。

矩阵乘法:

image-20220315225712452

矩阵 A A A 显然是存在的。

那么我们如果想求 F n F_n Fn

则有: F n = F n − 1 ⋅ A F_n = F_{n-1}·A Fn=Fn1A

所以: F n = F 1 ⋅ A n − 1 F_n = F_1·A^{n-1} Fn=F1An1

矩阵乘法是有结合律的,所以可以用快速幂来求。

接下来构造我们本题的矩阵, S n S_n Sn 是本题要求的前 n n n 项和:

image-20220315231417146

import java.util.Arrays;
import java.util.Scanner;

public class Main {

    static final int N = 3;
    static int n, m;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); m = sc.nextInt();
        long[] f1 = {1, 1, 1}; // f1 fn+1 S1
        long[][] a = { // A
                {0, 1, 0},
                {1, 1, 1},
                {0, 0, 1}
        };

        n--; // A^n-1
        while (n > 0) { // 快速幂模板
            if ((n & 1) == 1) mul(f1, f1, a); // res = res * a
            mul(a, a, a); // a = a * a
            n >>= 1;
        }

        System.out.println(f1[2]); // Sn
    }

    // 矩阵乘法
    private static void mul(long[] c, long[] a, long[][] b) {
        long[] temp = new long[N];
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                temp[i] = (temp[i] + a[j] * b[j][i]) % m;

        System.arraycopy(temp, 0, c, 0, N); // 拷贝数组
    }

    private static void mul(long[][] c, long[][] a, long[][] b) {
        long[][] temp = new long[N][N];
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                for (int k = 0; k < N; k++)
                    temp[i][j] = (temp[i][j] + a[i][k] * b[k][j]) % m;

        System.arraycopy(temp, 0, c, 0, N); // 拷贝数组
    }
}

第八届2017年蓝桥杯真题

完全背包问题

image-20220405155454589

朴素做法

import java.util.Scanner;

public class Main {

    static int N = 1010;
    static int v[] = new int[N];
    static int w[] = new int[N];
    static int f[][] = new int[N][N];

    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        for (int i = 1; i <= n; i++) {
            v[i] = sc.nextInt(); 
            w[i] = sc.nextInt();
        }
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= m; j++)
                for (int k = 0; k * v[i] <= j; k++)
                    f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
        System.out.println(f[n][m]);
    }
}

image-20220405155541591

优化做法

import java.util.Scanner;

public class Main {

    static int N = 1010;
    static int v[] = new int[N];
    static int w[] = new int[N];
    static int f[][] = new int[N][N];

    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        for (int i = 1; i <= n; i++) {
            v[i] = sc.nextInt(); 
            w[i] = sc.nextInt();
        }
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= m; j++){
                f[i][j] = f[i - 1][j];
                if (j >= v[i]) f[i][j] = Math.max(f[i][j], f[i][j - v[i]] + w[i]);
            }
        System.out.println(f[n][m]);
    }
}

AcWing 1226. 包子凑数

JavaB组第8题

完全背包问题+数论

假设我们有 N N N 个蒸笼,每个蒸笼的包子分别为 A 1 , A 2 . . . A n A_1,A_2...A_n A1,A2...An,且他们的最大公约数是 d d d,且 d > 1 d>1 d>1,所有数都是 d d d 的倍数,如果一个数不能被 d d d 整数,则说明这个数也一定不能被 A 1 , A 2 . . . A n A_1,A_2...A_n A1,A2...An 凑出来,所以此时会有正无穷 I N F INF INF 个数凑不出来。

g c d ( A 1 , A 2 . . . A n ) = 1 gcd(A_1,A_2...A_n)=1 gcd(A1,A2...An)=1 时,不能凑出来的数一定是有限个,这是依据裴蜀定理,裴蜀定理是基于两个数 a , b a,b a,b 的定理,当 g c d ( a , b ) = 1 gcd(a,b) = 1 gcd(a,b)=1 时,最大不能表示的数是: ( a − 1 ) ( b − 1 ) − 1 (a-1)(b-1)-1 (a1)(b1)1, 当有 N N N 个数时定理也同样适用,当数变多时,这个上界必然会更小,因为可选的数变多了,因为 1 ≤ N ≤ 100 1\leq N \leq 100 1N100,小于 100 100 100 中最大互质的两个数是 98 , 99 98,99 98,99,所以这里的上界我们取到 10000 10000 10000 即可。

此时这个问题就变成了完全背包问题,在 10000 10000 10000 以内有多少个数不能被组合出来。

闫式DP分析法

image-20220404153140404

此时的状态转移方程: f ( i , j ) = f ( i − 1 , j ) ∣ f ( i − 1 , j − A i ) ∣ f ( i − 1 , j − 2 A i ) ∣ . . . ∣ f ( i − 1 , j ≤ 0 ) f(i,j)=f(i-1,j)|f(i-1,j-A_i)|f(i-1,j-2A_i)|...|f(i-1,j\leq0) f(i,j)=f(i1,j)f(i1,jAi)f(i1,j2Ai)∣...∣f(i1,j0)

时间复杂度为 O ( N 3 ) O(N^3) O(N3),状态的数量是 N 2 N^2 N2 个,转移的数量是 N N N 个,显然是需要 优化一下的,一般的背包问题时间复杂度是 O ( N 2 ) O(N^2) O(N2)

我们做一下 j j j 的变量变换: f ( i , j − A i ) = f ( i − 1 , j − A i ) ∣ f ( i − 1 , j − 2 A i ) ∣ f ( i − 1 , j − 3 A i ) ∣ . . . f(i,j-A_i)=f(i-1,j-A_i)|f(i-1,j-2A_i)|f(i-1,j-3A_i)|... f(i,jAi)=f(i1,jAi)f(i1,j2Ai)f(i1,j3Ai)∣...

此时这个等式可以替换为第一个等式从第二项开始后面的所有项:

image-20220318224727280

状态转移方程优化为: f ( i , j ) = f ( i − 1 , j ) ∣ f ( i , j − A i ) f(i,j)=f(i-1,j)|f(i,j-A_i) f(i,j)=f(i1,j)f(i,jAi)

import java.util.Scanner;

public class Main {
    
    static final int N = 110, M = 10010;
    static int[] a = new int[N];
    static boolean[][] f = new boolean[N][M];
    
    public static void main(String[] args) {
    	Scanner sc = new Scanner(System.in);
    	int n = sc.nextInt();
    	int d = 0;
    	for (int i = 1; i <= n; i++) {
    	    a[i] = sc.nextInt();
    	    d = gcd(d, a[i]);
    	}

        if (d != 1) System.out.println("INF"); // 最大公约数不为1 有无限多个数凑不出来
        else {
            f[0][0] = true; // 0件物品 体积为0时也是一种方案
            for (int i = 1; i <= n; i++) {
                for (int j = 0; j < M; j++) {
                    f[i][j] = f[i - 1][j]; // 第一项一定存在
                    if (j >= a[i]) f[i][j] |= f[i][j - a[i]]; // 第二项不一定存在 用或"|"
                }
            }
            
            int res = 0;
            for (int i = 0; i < M; i++) {
                if (!f[n][i]) res++;
            }

    	    System.out.println(res);
        }
    }
    
    private static int gcd(int a, int b) {
        return b != 0 ? gcd(b, a % b) : a;
    }
}

我们发现我们的方程第 i i i 维只依赖于第 i i i i − 1 i-1 i1 项,所以我们可以将数组优化成一维:

import java.util.Scanner;

public class Main {
    
    static final int N = 110, M = 10010;
    static int[] a = new int[N];
    static boolean[] f = new boolean[M];
    
    public static void main(String[] args) {
    	Scanner sc = new Scanner(System.in);
    	int n = sc.nextInt();
    	int d = 0;
    	for (int i = 1; i <= n; i++) {
    	    a[i] = sc.nextInt();
    	    d = gcd(d, a[i]);
    	}

        if (d != 1) System.out.println("INF"); // 最大公约数不为1 有无限多个数凑不出来
        else {
            f[0] = true; // 0件物品 体积为0时也是一种方案
            for (int i = 1; i <= n; i++) {
                for (int j = a[i]; j < M; j++) {
                    f[j] |= f[j - a[i]];
                }
            }
            
            int res = 0;
            for (int i = 0; i < M; i++) {
                if (!f[i]) res++;
            }

    	    System.out.println(res);
        }
    }
    
    private static int gcd(int a, int b) {
        return b != 0 ? gcd(b, a % b) : a;
    }
}

第六届2015年蓝桥杯真题

AcWing 1217. 垒骰子

JavaB组第9题

DP+矩阵乘法+快速幂

img

我们要把 n n n 个骰子一个一个往上摞,骰子一共有6个面,本题是有 m m m 组互斥的数,假如互斥数是 1 , 2 1,2 1,2,那么骰子在垒时,上下两个紧贴的面就不能是 1 1 1 2 2 2,求有多少种不同垒骰子的方案数。

闫式DP分析法

image-20220403132938173

当然这是没有去掉不合理的方案总数。

这题太难理解了,没有继续了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《 乱弹篇(三)》

题记 前两篇《乱弹》&#xff0c;一是乱弹了“北宋名相寇准的《六悔铭》”&#xff0c;并议及“不择手段&#xff0c;只谋功利”&#xff1b;二是乱弹了晚清重臣、湘军统帅曾国藩的为官之道和处世哲学&#xff0c;并介绍了他在《冰鉴》一书里用来识人的对联和口诀。 这两篇《…

网络安全自学入门:(超详细)从入门到精通学习路线规划,学完即可就业

很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习&#xff0c;最终也只是会无疾而终&#xff01;黑客是一个大的概念&#xff0c;里面包含了许多方向&#xff0c;不同的方向需要学习的内容也不一样。 算上从学校开始学习&#xff0c;已经在网安这条路上走…

第08章_面向对象编程(高级)拓展练习(关键字:static,代码块,关键字:final,抽象类和抽象方法,接口,内部类,枚举类,注解,包装类)

文章目录 第08章_面向对象编程&#xff08;高级&#xff09;拓展练习01-关键字&#xff1a;static1、银行账户类2、图形类3、数组工具类4、二分查找5、二分查找6、素数7、阅读代码&#xff0c;分析运行结果8、阅读代码&#xff0c;分析运行结果 02-代码块9、阅读代码&#xff0…

【嘉立创EDA-PCB设计指南】1.PCB基本概念及原理图绘制

前言&#xff1a;本文详解PCB基本概念以及实现MCU最小系统原理图的绘制&#xff08;原理图包括MCU芯片GD32F103C8T6、外部晶振、输出端口、USB输入口、5v转3v3稳压输出、复位按键、唤醒按键、LED&#xff09;。为本专栏后面章节实现PCB绘制做准备。 最终绘制的原理图如下所示&…

鸿蒙开发-UI-布局-层叠布局

鸿蒙开发-UI-布局 鸿蒙开发-UI-布局-线性布局 文章目录 前言 一、基本概念 二、对齐方式 三、Z序控制 四、使用场景 总结 前言 上文详细学习了线性布局&#xff0c;学习了线性容器内子元素在主轴以及交叉轴上的排列方式&#xff0c;子元素自适应相关的知识点&#xff0c;本文继…

强化学习(二)多臂老虎机 “Multi-armed Bandits”——2

1、增量算法估计动作价值 由之前的内容可知&#xff0c;某一个动作被选择 n − 1 n-1 n−1 次后&#xff0c;该动作的价值估计值为 Q n ≐ R 1 R 2 ⋯ R n − 1 n − 1 Q_n\doteq\dfrac{R_1R_2\cdotsR_{n-1}}{n-1} Qn​≐n−1R1​R2​⋯Rn−1​​ 很明显&#xff0c;随着…

小规模团队更适合什么样的客户管理系统?

小规模团队更适合什么样的客户管理系统&#xff1f; 一般情况下&#xff0c;小规模对客户管理系统的需求通常有以下特点&#xff1a; 团队规模&#xff1a;小规模&#xff0c;不超过10人——尽可能降低使用成本使用人员&#xff1a;销售人员使用——无代码基础&#xff0c;最…

学习JavaEE的日子 day12 构造方法 类的制作

Day12 需求&#xff1a;创建人类的对象&#xff0c;并操作对象 分析&#xff1a; 人类 - Person 属性&#xff1a;name、sex、age 方法&#xff1a;eat、sleep 场景&#xff1a;创建多个对象&#xff0c;去操作对象 //测试类&#xff1a;该类中有main方法&#xff0c;测试我们写…

Mybatis配置动态数据源以及参数传递等

Mybatis必知必会 一、Mybatis动态加载数据源 在配置数据源连接时,在企业的真实开发中数据源一般都会写在配置文件中&#xff0c;而不会直接写在mybatis的核心配置文件中 所以,Mybatis为了方便开发人员去动态的获取数据源连接制定了一些特定的标签用于加载这些数据源。 具体做法…

【leetcode刷题】模拟专题

模拟 一、替换所有的问号1、题目链接2、解析3、代码 二、提莫攻击1、题目链接2、解析3、代码 三、Z字形变换1、题目链接2、解析3、代码 四、外观数列1、题目链接2、解析3、代码 五、数青蛙1、题目链接2、解析3、代码 一、替换所有的问号 1、题目链接 leetcode链接 2、解析 3、…

2024年人才缺口大,学网络安全找不到工作?原因竟然在这!

为什么网络安全人才缺口那么大&#xff0c;但很多人还是找不到工作&#xff1f;其实大家都忽略了1个重点&#xff0c;那就是不清楚企业在招什么样的人。 我花了2天的时间统计了主流招聘网站的岗位信息&#xff0c;发现了一个惊人的真相&#xff0c;那就是企业都喜欢招这3种人&…

深度学习笔记(四)——使用TF2构建基础网络的常用函数+简单ML分类实现

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解&#xff0c;如有遗漏或错误&#xff0c;欢迎评论或私信指正。 截图和程序部分引用自北京大学机器学习公开课 TF2基础常用函数 1、张量处理类 强制数据类型转换&#xff1a; a1 tf.constant([1,2,3], dtypetf.floa…

Android APP开发集成微信登陆流程(手把手新手版)

本文比较适合新手玩家&#xff0c;老玩家就不要看了 昨天整了下微信登陆&#xff0c;乍一看官方文档还有点难懂&#xff01;遂自己整理了下流程&#xff0c;给大家参考参考。 官方文档链接&#xff1a;准备工作 | 微信开放文档微信开发者平台文档https://developers.weixin.q…

智能代码:生成式 AI 在软件开发中的革命性角色

想象一下&#xff0c;在智能手机革命性地改变了我们的生活之后&#xff0c;现在轮到了生成式 AI 在软件开发领域掀起风暴。你知道吗&#xff0c;如果代码能自己编写自己&#xff0c;这将是多么惊人的一步&#xff1f;这就好比我们现在能轻松地用手机应用管理日常生活一样&#…

AI大模型预先学习笔记三:使用Assistants API快速搭建领域专属AI助手

文章目录 一、什么是AssistantsAPI二、为什么用AssistantsAPI三、Demo展示及能力介绍四、Demo框架及具体实现五、从Demo到实际应用的Gap 一、什么是AssistantsAPI 介绍 OpenAI的第一手发布者API文档&#xff0c;也就是相当于GPT的API 二、为什么用AssistantsAPI 优点 够全、…

vue 渲染数组,拖拽排序,渲染同一个数组拖拽排序不影响其他选中行状态

当我们能够设置单行状态改变的时候&#xff0c;那么肯定可以拿到选中的当前行的id或者下标index。 只要设定一个初始化值在拖拽开始的时候重新赋值&#xff0c;然后再处理选中状态的时候进行判断即可。 前期写的时候没有注意到这个问题&#xff0c;可以看这个文章。 在复测的时…

解析HTTP响应的JSON数据

解析HTTP响应的JSON数据是许多Web开发任务中的常见需求。在Go语言中&#xff0c;可以使用标准库中的encoding/json包来轻松解析JSON数据。下面我将详细介绍如何解析HTTP响应的JSON数据。 首先&#xff0c;确保你已经发送了一个HTTP请求并获取到了响应。然后&#xff0c;你可以…

变电站综合自动化监控系统在某物流园35kV变电站中应用

摘 要&#xff1a;Acrel-1000变电站综合自动化系统&#xff0c;是我司根据电力系统自动化及无人值守的要求&#xff0c;总结国内外的研究和生产的先进经验&#xff0c;专门研制出的新一代电力监控系统。本系统具有保护、遥测、遥信、遥脉、遥调、遥控功能&#xff0c;可实现无人…

博途PLC增量式PID和脉冲轴组合控制阀门开度(算法介绍)

这篇博客我们以S7-1200PLC平台来举例,介绍我们的PID闭环控制器如何控制脉冲轴实现阀门角度控制。SMART PLC PID控制器控制伺服驱动器实现关节角度控制详细内容请参考下面文章: https://rxxw-control.blog.csdn.net/article/details/129658364https://rxxw-control.blog.csdn…

HNU-计算机网络-实验5(自选)-安全相关编程实验

计算机网络 课程综合实验安全相关编程实验&#xff08;RUST&#xff09; 计科210X 甘晴void 202108010XXX 【前言】 这个《课程综合实验》是21级开始新加的实验&#xff0c;之前都没有。具体的可以看实验指导书&#xff0c;是用的19级同学的毕设。我完成的这个实验需要一点点R…