AcWing 4378. 选取数对
2024-09-08 07:21:19
y总分析:这种题(我也不知道说的是哪种题hh)一般解法为贪心或dp,而本题用的是dp。
其实个人感觉题目不是很严谨,从y总讲解和题解分析得知各个数对区间是不能重叠的,但是题目使用的是≤,感觉数对的区间边界点是可以重复的。
方法1:y总的讲解,个人感觉比较难理解,也没有完全理解,因此只贴一个链接:第一届ACC(AcWing Cup)全国高校联赛_哔哩哔哩_bilibili
方法二:AcWing 4378. 选取数对(闫式dp分析法,但是要比y总讲的简单) - AcWing
思路:
闫式dp分析法
状态表示f[i][j]:表示在前i个数中选,j个区间的所有集合,属性:max
状态计算f[i][j]:根据最后一个区间是否包含最后一个点i来进行集合划分
1.不包含:f[i][j]=max(f[i][j],f[i-1][j])
2.包含:f[i][j]=max(f[i][j],f[i-m][j-1]+sum[i]-sum[i-m]) //如果包含i的话最后一个区间的右端点就是i
Java代码实现:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
*
*/
public class Main {
static int N=5000+5;
//下标从1开始
//f[i][j]的意思是从前i个数中选择k个数对
static long[][] f=new long[N][N];
static long[] sum=new long[N];
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] line = reader.readLine().split(" ");
int n=Integer.parseInt(line[0]);
int m=Integer.parseInt(line[1]);
int k=Integer.parseInt(line[2]);
line=reader.readLine().split(" ");
//录入数据并计算前缀和
for (int i = 0; i < n; i++) {
sum[i+1]=Long.parseLong (line[i]);
sum[i+1]+=sum[i];
}
for (int i = 1 ; i <= n; i++) {
for (int j = 1; j <= k; j++) {
//不选择第i个数
f[i][j]=f[i-1][j];
//如果选择第i个数作为末尾
//不选择第i个数是无条件的,但是选择第i个数作为末尾必须保证:此数对可以选择,即此数对第一个数下标必须≥1
if (i-m+1>=1) {
f[i][j]=Math.max(f[i][j], f[i-m][j]+sum[i]-sum[i-m]);
}
}
}
System.out.println(f[n][k]);
}
}
方法三:https://www.acwing.com/solution/content/72485/
思路
和方法二本质上是相同的,只是进行了预处理,直接将原数组转换成了最终的一个一个数对的和值数组,然后也是最后一个数块的选择与否来进行集合的划分。
c++代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5010;
ll n,m,k;
ll a[N],b[N];
ll w[N];
ll f[N][N];
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=b[i-1]+a[i];
}
ll cnt=0;
for(int i=1;i+m-1<=n;i++)
{
//先将每个数对的之间的和单独做成一个数组,w即为此数组
w[++cnt]=b[i+m-1]-b[i-1];//预处理区间
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=k;j++)
{
//i-m<0 因为数块下标从0开始,表示此数块如果选择的了的话就不能选择其他块了(取w[i])
//f[i][j]=max(不选此块,选此块);
if(i-m<0) f[i][j]=max(f[i-1][j],w[i]);//此时最多选择一个区间
//如果此数块可以选择,那么就在选择该块和不选之间取最大值。
//即f[i][j]=max(不选此块,选此块);
else f[i][j]=max(f[i-1][j],f[i-m][j-1]+w[i]);
}
}
cout<<f[cnt][k];
return 0;
}
最新文章
- [问答] Firemonkey 控件继承后无法显示(空白)
- 控制反转IOC的依赖注入方式
- np2016课程总结
- GitHub Top 100的Android开源库
- Eclipse,IDEA自动生成相应对象接收方法返回值的快捷键
- COUNT(*)与COUNT(列名)的区别(转)
- Stage3D学习笔记(二):使用GPU绘制一个三角形
- (poj)1806 Currency Exchange
- Java面试题收集学习整理1
- 函数:atexit
- 命令查看服务器SN号
- Jmeter脚本录制方法(二)——手工编写脚本(jmeter与fiddler结合使用)
- Android摄像头照相机技术-android学习之旅(八)
- mysql基础优化-explain的使用-mysql死锁
- [转]centos每天自动备份mysql数据库
- ecstore Fatal error: Class &#39;base_request&#39; not found
- IntelliJ IDEA 编译Java程序出现 &#39;Error:java: 无效的源发行版: 9&#39; 的解决方案
- ASP.NET MVC - 多国语言的简单实现
- [转]清理ambari安装的hadoop集群
- HGOI20180817 (NOIP模拟Day1 task)
热门文章
- python pymysql连接数据库并创建表
- webpack 4.0 配置方法以及错误解决
- An=n的前n项和的前n项和
- 不用关闭重启cad及不用更改快捷方式或者版本号c#调试cad插件
- 使用 Jenkins 进行持续集成与发布流程图-图解
- Hyperledger Fabric定制联盟链网络工程实践
- sqlplus文件查看自带oracle命令的执行过程
- SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(上)
- Codeforces Round #741 (Div. 2), problem: (D1) Two Hundred Twenty One (easy version), 1700
- js实时监听dom尺寸变化