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;
}

最新文章

  1. [问答] Firemonkey 控件继承后无法显示(空白)
  2. 控制反转IOC的依赖注入方式
  3. np2016课程总结
  4. GitHub Top 100的Android开源库
  5. Eclipse,IDEA自动生成相应对象接收方法返回值的快捷键
  6. COUNT(*)与COUNT(列名)的区别(转)
  7. Stage3D学习笔记(二):使用GPU绘制一个三角形
  8. (poj)1806 Currency Exchange
  9. Java面试题收集学习整理1
  10. 函数:atexit
  11. 命令查看服务器SN号
  12. Jmeter脚本录制方法(二)——手工编写脚本(jmeter与fiddler结合使用)
  13. Android摄像头照相机技术-android学习之旅(八)
  14. mysql基础优化-explain的使用-mysql死锁
  15. [转]centos每天自动备份mysql数据库
  16. ecstore Fatal error: Class &#39;base_request&#39; not found
  17. IntelliJ IDEA 编译Java程序出现 &#39;Error:java: 无效的源发行版: 9&#39; 的解决方案
  18. ASP.NET MVC - 多国语言的简单实现
  19. [转]清理ambari安装的hadoop集群
  20. HGOI20180817 (NOIP模拟Day1 task)

热门文章

  1. python pymysql连接数据库并创建表
  2. webpack 4.0 配置方法以及错误解决
  3. An=n的前n项和的前n项和
  4. 不用关闭重启cad及不用更改快捷方式或者版本号c#调试cad插件
  5. 使用 Jenkins 进行持续集成与发布流程图-图解
  6. Hyperledger Fabric定制联盟链网络工程实践
  7. sqlplus文件查看自带oracle命令的执行过程
  8. SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(上)
  9. Codeforces Round #741 (Div. 2), problem: (D1) Two Hundred Twenty One (easy version), 1700
  10. js实时监听dom尺寸变化