【神仙DP】【单调队列】【模拟题】区间覆盖
Description
给出数轴上的n个线段,保留最多k条线段,问这些被保留下来的线段的并集长度为最多为多少。
Input
第一行两个数n和k
接下来n行,每行两个数,表示一条线段的左右端点。(0<=每个数<109)
Output
一个数表示答案。
Sample Input
Sample Output
Hint
对于30%的数据,1<=n<=20
对于60%的数据,1<=n<=300
对于100%的数据,1<=n<=100000,,1<=k<=min(100,n);
Solution
想了半天,看这个数据范围大概是nlogn可过,n*k也可过。先考虑贪心,貌似可行,但是贪心的复杂的是O(kn2logn)……手动再见还不如朴素DP。
考虑DP。朴素DP十分好想,按区间右端点排序,设f[i][j]为前i个线段选j个,其中必选i。这样易得转移方程:
f[i][j]=max(max{f[h][j-1]+r[i]-l[i]|l[i]>=r[h]},max{f[h][j-1]+r[i]-r[h]|l[i]>=r[h]})。
直观上,方程表示从前h个选j-1个开始转移,按区间是否有交划分转移。
如此转移,需要枚举当前区间,当前区间前的区间,以及线段个数,时间复杂度为O(n2k)。期望得分50分。
下面我进行了许多毫无卵用的优化:
观察前半个转移方程,需要找到前h个中最大的f[h][j-1]。显然线段树可以保存区间最大值,于是对于前半段线段树优化。这样就无需枚举h。那么如何确定h呢?考虑因为右端点满足单调性,于是进行二分。二分h的位置。复杂度O(logn)。对于后半个方程,想破脑袋也只能枚举转移,这样在期望状态下,复杂度为O(nklog2n)。两个log一个是线段树的一个是二分的。于是我们发现,我们的期望得分仍然是50分……
这是跑的最快的50分做法。差点卡常卡过70分。
下面是正解:
对于前半部分方程,需要取前i个的最大值,显然前缀最大值可做。即Max[i][j]=max(Max[i-1][j],frog[i][j])这样,对于前半部分的转移,转移时间从O(logn)降低到了O(1)。可是这样期望还是50分啊。考虑最大h的位置。由于满足右端点递增,如果在排序是将左端点为第二关键字升序排序,那么显然h是递增的。因为h代表的是右端点小于等于l[i]的右端点区间最大的编号。由于r[i]递增,l[i]升序,所以l[i]递增。(对于相互包含的区间,显然大区间优于小区间,需要去重)这样只需要不断++h,判断h是否合法即可。这样,决策时间也降到了O(1)。下面考虑对于后半部分方程的转移。由于r[i]、l[i]递增,所以满足第二部分方程的h是递增的。如此可以进行单调队列优化。对于合法的但是小的f,会被新进队列的元素直接覆盖。不合法的会从队首弹出。如此,整个转移的复杂度被降到了O(1)。所以本题的复杂度为Θ(nk+n+nlogn),其中nk为DP,n为单调队列总维护次数,nlogn为排序复杂的。即O(nk)。这样复杂度就合法通过了本题。
Code
#include<cstdio>
#include<algorithm>
#define maxn 100010 inline void qr(int &x) {
char ch=getchar();bool f=false;
while(ch>''||ch<'') {
if(ch=='-') f=true;
ch=getchar();
}
while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
if(f) x=-x;
} inline int max(const int &a,const int &b) {if(a>b)return a;else return b;}
inline int min(const int &a,const int &b) {if(a<b)return a;else return b;}
inline int abs(const int &x) {if(x>=) return x;else return -x;} inline void swap(int &a,int &b) {
int temp=a;a=b;b=temp;
} int n,k,ans;
struct M {
int l,r;
};
M MU[maxn];
int frog[maxn][];
inline bool cmp(const M &a,const M &b) {
if(a.r!=b.r) return a.r<b.r;
return a.l<b.l;
} int main() {
freopen("cover10.in","r",stdin);
freopen("ans.out","w",stdout);
qr(n);qr(k);
for(int i=;i<=n;++i) {
qr(MU[i].l);qr(MU[i].r);
}
std::sort(MU+,MU++n,cmp);
for(int i=;i<=n;++i) {
frog[i][]=MU[i].r-MU[i].l;
for(int j=k;j>;--j) {
for(int h=;h<i;++h) {
if(MU[h].r<=MU[i].l) frog[i][j]=max(frog[i][j],frog[h][j-]+MU[i].r-MU[i].l);
else frog[i][j]=max(frog[i][j],frog[h][j-]+MU[i].r-MU[h].r);
}
}
ans=max(ans,frog[i][k]);
}
printf("%d\n",ans);
return ;
}
50分无优化
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
ld eps=1e-;
ll pp=;
ll mo(ll a,ll pp){if(a>= && a<pp)return a;a%=pp;if(a<)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=;for(;b;b>>=,a=mo(a*a,pp))if(b&)ans=mo(ans*a,pp);return ans;}
ll read(){
ll ans=;
char last=' ',ch=getchar();
while(ch<'' || ch>'')last=ch,ch=getchar();
while(ch>='' && ch<='')ans=ans*+ch-'',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}
//head
#define N 110000
ll f[][N];
pr a[N];
int n,k,nn,q[N];
ll b[N],c[N];
int main(){
freopen("cover.in","r",stdin);
freopen("cover.out","w",stdout);
n=read();k=read();
rep(i,,n)a[i].first=read(),a[i].second=read();
sort(a+,a+n+);
nn=;
rep(i,,n)
if(a[nn].second<a[i].second)a[++nn]=a[i];
n=nn;k=min(k,n);
rep(i,,)
rep(j,,n)f[i][j]=-;
f[][]=;
int ans=;
rep(i,,k-){
b[]=f[][];
rep(j,,n)b[j]=max(f[][j],b[j-]);
rep(j,,n)c[j]=f[][j]-a[j].second;
int t=,w=,z=;
rep(j,i+,n){
while(a[z+].second<=a[j].first)++z;
while(t<=w && c[j-]>=c[q[w]])--w;
q[++w]=j-;
while(t<=w && q[t]<=z)++t;
f[][j]=b[z]+a[j].second-a[j].first;
if(t<=w)f[][j]=max(f[][j],c[q[t]]+a[j].second);
ans=max((ll)ans,f[][j]);
}
rep(j,,n)f[][j]=f[][j],f[][j]=-;
} printf("%d\n",ans);
return ;
}
Summary
1、在需要前i个元素中最大值且i转移单调时,考虑前缀最大值而不是线段树。这样复杂度可以下降为O(1)。其实我就是数据结构学傻了
2、转移区间满足单调性时,考虑单调队列优化。需要注意的是,单调队列中单调的是元素下标而不是DP值。这不是废话吗
3、神仙题优化时可以画图考虑转移位置,从而发现性质。
【神仙DP】【单调队列】【模拟题】区间覆盖的更多相关文章
- (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列
Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...
- [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)
DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...
- Sliding Window POJ - 2823 单调队列模板题
Sliding Window POJ - 2823 单调队列模板题 题意 给出一个数列 并且给出一个数m 问每个连续的m中的最小\最大值是多少,并输出 思路 使用单调队列来写,拿最小值来举例 要求区间 ...
- DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)
codevs 1748 瑰丽华尔兹 2005年NOI全国竞赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Descripti ...
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
题目链接 首先二分答案L.然后就是判断能否将原串划分出一些长度不小于L的子串,这些子串要是给定n个串中的某个串的子串,且满足它们的长度之和不小于原串长度的90%. 贪心多长选一段什么的显然不对.老老实 ...
- 3622 假期(DP+单调队列优化)
3622 假期 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Description 经过几个月辛勤的工作,FJ决定让奶牛放假.假期可以在1-N天内任意选择 ...
- 习题:烽火传递(DP+单调队列)
烽火传递[题目描述]烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有n个烽火台,每个烽火台 ...
- luoguP1886 滑动窗口(单调队列模板题)
题目链接:https://www.luogu.org/problem/P1886#submit 题意:给定n个数,求大小为k的滑动窗口中最小值和最大值. 思路:单调队列模板题. AC代码: #incl ...
- BZOJ4560 JLOI2016字符串覆盖(kmp+贪心+状压dp+单调队列)
首先kmp求出每个子串能放在哪些位置.接下来的两部分贪心和状压都可以,各取比较方便的. 最大值考虑贪心.考虑枚举子串的左端点出现顺序,在此基础上每个子串的位置肯定都应该尽量靠前,有是否与上个子串有交两 ...
- Codeforces 940 区间DP单调队列优化
A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...
随机推荐
- 使用jenkins构建一个自由风格的项目
一.创建一个freestyle风格的构建项目 二.输入任务名称和选择任务类型 三.配置项目 3.1:选择代码托管 3.2:到gitlab上去配置deploy key 3.3:到jenkins服务器去生 ...
- Maxscript-获取选中文件
Maxscript - 获取选中文件 使用 .Net 的方法弹出窗口选择文件,并范围所有选中文件的路径“” Fn Fun_GetFilePaths strTitle strFilter = ( dia ...
- java后台接受web前台传递的数组参数
前台发送:&warning_type[]=1,2 &warning_type=1,2 后台接收:(@RequestParam(value = "param[]") ...
- 【form】 表单组件说明
form表单组件 1)将form组件内的用户输入的<switch/> <input/> <checkbox/> <slider/> <radio/ ...
- django 增删改查操作 数据库Mysql
下面介绍一下django增删改查操作: 1.view.py # -*- coding: utf-8 -*-from __future__ import unicode_literalsfrom dja ...
- Android开发-API指南-<uses-permission>
<uses-permission> 英文原文:http://developer.android.com/guide/topics/manifest/uses-permission-elem ...
- 承压计算:模拟+double
标题:承压计算 X星球的高科技实验室中整齐地堆放着某批珍贵金属原料. 每块金属原料的外形.尺寸完全一致,但重量不同.金属材料被严格地堆放成金字塔形. 7 ...
- Hadoop,MapReduce操作Mysql
前以前帖子介绍,怎样读取文本数据源和多个数据源的合并:http://www.cnblogs.com/liqizhou/archive/2012/05/15/2501835.html 这一个博客介绍一下 ...
- POJ 2826 An Easy Problem?!(线段交点+简单计算)
Description It's raining outside. Farmer Johnson's bull Ben wants some rain to water his flowers. Be ...
- POJ 1739 Tony's Tour(插头DP)
Description A square township has been divided up into n*m(n rows and m columns) square plots (1< ...