AcWing 5386. 进水出水问题【线性dp+差值dp】

2024-01-15 00:52

本文主要是介绍AcWing 5386. 进水出水问题【线性dp+差值dp】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原题链接:https://www.acwing.com/problem/content/5389/

某泳池装有 n 个水管,编号 1∼n。

每个水管都是既可用于进水,也可用于出水。

其中,第 i 个水管工作时的单位时间进水或出水量为 ai。

我们希望泳池保持水循环的同时,还能够保持水位不变。

为此,我们需要制定一种水管工作方案。

具体要求为:

  1. 选择若干个(至少一个)连续编号的水管作为工作水管(未选择的水管不工作)。
  2. 每个工作水管,要么用于进水,要么用于出水。
  3. 所有安排完毕以后,所有用于进水的工作水管的进水量之和应当等于所有用于出水的工作水管的出水量之和。

请你计算,一共可以制定出多少种不同的水管工作方案。

注意,(1 号水管进水、2 号水管出水)和(1 号水管出水、2 号水管进水)应当视为两种不同的方案,虽然它们用到的工作水管相同,但是水管的具体安排(进水或出水)不同。

输入格式

第一行包含整数 n。

第二行包含 n 个整数 a1,a2,…,an。

输出格式

一个整数,表示可以制定出的不同方案的总数量对 1e9+7 取模后的结果。

数据范围

前 3 个测试点满足 1≤n≤10。
所有测试点满足 1≤n≤1000,1≤ai≤1000,ai<=10000(1<=i<=n)

输入样例:
4
1 1 1 1
输出样例:
12
解题思路:

首先看到这种求方案数,又有方案数可能很大需要取模,那么这个题目十有八九就是可以推出数学公式或者就是dp,,但是我没有发现可以推出什么公式,但是从题目可以看到俩个操作,对于选定工作的水管,要么用于进水,要么用于出水,这很像线性dp的常规操作,我首先想到的就是首先枚举所有区间然后对于每个区间进行线性dp,但是这个方法时间复杂度太高了,根本过不了, 而且也找不到很好的优化方式,看到n=1000,如果先枚举所有区间再dp显然是不现实的,我们可以看看有没有什么好的状态定义方式使得不需要暴力枚举所有区间,而是可以直接设置状态进行dp呢,我们可以发现题目要求选择的一段连续工作水管的进水量和出水量需要相同,涉及到俩个变量,进水量之和最多是0-10000,出水量之和最多是0-10000,同时要使得进水量之和和出水量之和相同就是要使得进水量和出水量的差值为0,这个时候我们看到了差值这个词,那么我们可以尝试使用差值设计状态,以前貌似没见过这种差值状态设计,所以这次确实没有想出来这样设计状态。

状态定义:

定义:f[i][j]表示以i结尾并且进水量和出水量的差值为j的所有方案

初始状态:

正常情况下,我们会设f[0][0]=1,但是这个题目不能这样设初始状态,如果这样设初始状态,当i==1时,会导致(1)(3)或者(2)(4)出现重复计算情况,所以我们不这样设初始状态,出现这种情况是因为当i==1时,第(3)种情况虽然定义的是前面还有管子,但是在当前是第一根管子时,前面根本就没有管子了,导致此时第(3)变为了和(1)一样,相当于这种情况被计算了俩次,导致了重复计算。我们将所有的f[i][a[i]]和f[i][-a[i]]初始值定为1即可,因为工作的水管必须是连续的,所以状态定义状态转移时不仅需要考虑当前位置进水或者出水,而且还需要考虑当前位置前面还有没有工作的水管,所以这就是为什么我们的初始状态不能按照常规方式去设的原因,也是常规做法状态转移只有俩种情况,但是这里有四种状态转移情况的原因。

状态转移:

(1)当前位置管子设为进水,并且前面没有工作管子了

f[i][a[i]]++;

(2)当前位置管子设为出水,并且前面没有工作管子了

f[i][-a[i]]++;

(3)当前位置管子设为进水,并且前面还有工作管子

f[i][j]=(f[i][j]+f[i-1][j-a[i]])

(4)当前位置管子设为出水,并且前面还有工作管子

f[i][j]=(f[i][j]+f[i-1][j+a[i]]);

最终答案

答案是所有的f[i][0]的和

注意由于我们定义的是差值,所以我们这个状态转移方程会出现负数下标,我们需要对状态转移方程做一个等价偏移,a数组所有数的和最大是10000,所以出现的负数最小值为-10000,我们设置偏移值为10000即可。

时间复杂度:第一维枚举水管,时间为O(n),第二位枚举差值时间为O(20000),最终时间为1000*20000,大概是2e7,这个时间复杂度是可以过的。

空间复杂度:2e7/1e6*8=160,大概是160M,题目给了256M,所以空间是足够的,如果我们将f定义为int类型,那么可以将空间降低到80M,这个题目给了256M,所以f数组定义为long long 类型也是可以的。

cpp代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;
typedef long long LL;const int N=1010,M=20010,mod=1e9+7,B=10000;  //B为偏移值int n;
int a[N];
LL f[N][M];  //f[i][j]表示以i结尾并且进水值和出水值之差为j的所有方案
int main()
{cin>>n;for(int i=1;i<=n;i++)scanf("%d",&a[i]);int res=0;for(int i=1;i<=n;i++){   //开始的范围是-10000~10000,偏移之后就是0~20000for(int j=0;j<=20000;j++){//当前位置进水if(j-a[i]>=0)f[i][j]=(f[i][j]+f[i-1][j-a[i]])%mod;//当前位置出水if(j+a[i]<=20000)f[i][j]=(f[i][j]+f[i-1][j+a[i]])%mod;}//设置f[i][a[i]]和f[i][-a[i]]的初始值为1f[i][B+a[i]]++,f[i][B-a[i]]++;res=(res+f[i][B])%mod;  //对于所有的f[i][0]求和就是答案,偏移之后是f[i][B]}cout<<res<<endl;return 0;
}

总结:之前貌似没有遇到过这种状态设计方式,所以当时没想出来,这次学会了,吸取教训,下次还遇到类似的希望能很快就想出来状态设计吧。 

这篇关于AcWing 5386. 进水出水问题【线性dp+差值dp】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/607085

相关文章

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

maven异常Invalid bound statement(not found)的问题解决

《maven异常Invalidboundstatement(notfound)的问题解决》本文详细介绍了Maven项目中常见的Invalidboundstatement异常及其解决方案,文中通过... 目录Maven异常:Invalid bound statement (not found) 详解问题描述可

idea粘贴空格时显示NBSP的问题及解决方案

《idea粘贴空格时显示NBSP的问题及解决方案》在IDEA中粘贴代码时出现大量空格占位符NBSP,可以通过取消勾选AdvancedSettings中的相应选项来解决... 目录1、背景介绍2、解决办法3、处理完成总结1、背景介绍python在idehttp://www.chinasem.cna粘贴代码,出

SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)

《SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)》本文总结了SpringBoot项目整合Kafka启动失败的常见错误,包括Kafka服务器连接问题、序列化配置错误、依赖配置问题、... 目录一、Kafka服务器连接问题1. Kafka服务器无法连接2. 开发环境与生产环境网络不通二、序

SpringSecurity中的跨域问题处理方案

《SpringSecurity中的跨域问题处理方案》本文介绍了跨域资源共享(CORS)技术在JavaEE开发中的应用,详细讲解了CORS的工作原理,包括简单请求和非简单请求的处理方式,本文结合实例代码... 目录1.什么是CORS2.简单请求3.非简单请求4.Spring跨域解决方案4.1.@CrossOr

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在

解决java.util.RandomAccessSubList cannot be cast to java.util.ArrayList错误的问题

《解决java.util.RandomAccessSubListcannotbecasttojava.util.ArrayList错误的问题》当你尝试将RandomAccessSubList... 目录Java.util.RandomAccessSubList cannot be cast to java.

Apache服务器IP自动跳转域名的问题及解决方案

《Apache服务器IP自动跳转域名的问题及解决方案》本教程将详细介绍如何通过Apache虚拟主机配置实现这一功能,并解决常见问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录​​问题背景​​解决方案​​方法 1:修改 httpd-vhosts.conf(推荐)​​步骤

java反序列化serialVersionUID不一致问题及解决

《java反序列化serialVersionUID不一致问题及解决》文章主要讨论了在Java中序列化和反序列化过程中遇到的问题,特别是当实体类的`serialVersionUID`发生变化或未设置时,... 目录前言一、序列化、反序列化二、解决方法总结前言serialVersionUID变化后,反序列化失

C++ 多态性实战之何时使用 virtual 和 override的问题解析

《C++多态性实战之何时使用virtual和override的问题解析》在面向对象编程中,多态是一个核心概念,很多开发者在遇到override编译错误时,不清楚是否需要将基类函数声明为virt... 目录C++ 多态性实战:何时使用 virtual 和 override?引言问题场景判断是否需要多态的三个关