#C241004B. 方差


#C241004B. 方差

标签(Label)

  • 动态规划

网址(Website)

题目详情 - 方差 - Super

题解 - 方差 - Super

题目(Problem)

详情如下

题目描述

现在有 $n$ 个区间 $[l_i, r_i]$,每个区间有个权值 $w_i$。 我们把这 $n$ 个区间当成 $n$ 个点,如果两个区间它们之间有交(包括端点),那么我们就在这两个区间之间连边,形成了一个区间图。

现在希望你删除一些区间,使得每个连通块大小不超过 $k$。

输出删除区间最小的权值和。

输入格式

从文件 variance.in 中读入数据。

第一行两个整数 $n, k$。

接下来 $n$ 行,每行三个整数 $l_i, r_i, w_i$。

输出格式

输出到文件 variance.out 中。

输出一个整数,表示答案。

样例

输入数据 1

5 2
1 4 1
3 6 2
5 8 5
7 10 2
9 12 1

输出数据 1

3

【输入输出样例2】

见选手目录下的 variance/variance2.invariance/variance2.ans

数据规模与约定

一共 10 个测试点。

对于测试点 1,2,保证 $n \leq 20$。

对于测试点 3,4,保证 $n \leq 100$。

对于测试点 5,6,保证 $n \leq 500$。

对于所有测试点,保证 $1 \leq k \leq n \leq 2500$;$1 \leq l_i \leq r_i \leq 10^9$;$1 \leq w_i \leq 10^9$。

题解(Solution)

$\qquad$根据连边的方式分析,如果要分开一个连通块,一定要把包含某个点的所有区间。

$\qquad$我们令 $f[i]$ 表示从 $1$ 到 $2n$ (离散化后最多 $2n$ 个点)枚举,当前枚举到 $i$ ,此时能取得的最大的贡献,将所有区间按右端点排序,如果 $i$ 到了右端点就加入区间,向前枚举 $j$ ,表示上一个删除的点,很容易处理出中间的区间有哪些,用一个优先队列,每次只取权值前 $k$ 大的区间保留,其他的删除,最后用总权值减去 $f[2n]$ 即可。

$\qquad$时间复杂度 $O(n^2\log n)$ 。

出题者题解

算法分析

可以发现,最后肯定是删除经过某些位置的所有区间。

记 $dp[i]$,表示当前切到 $i$ 这个位置,然后枚举上一段切什么地方 $j$,然后考虑 $[i,j]$ 之间的区间只保留价值最大的 $k$ 个,把其他的都删了,这样直接做是 $O(n^3 \log n)$ 的。从后往前枚举 $j$,依次加入区间,然后用堆维护一下前 $k$ 大即可,时间复杂度 $O(n^2 \log n)$,但是实际很快。

代码(Code)

#include<bits/stdc++.h>
#include<vector>
#include<queue>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int>
#define int long long
#define x first
#define y second
inline int rd(){int x;return cin>>x,x;}
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 201234;
bool ST;

int a[N],b[N],v[N];
int c[N],f[N];
int n,m,s,tot=0;
priority_queue<int> q;
vector<P> g[N];
vector<int> h[N];

inline void solve(){
	n = rd(), m = rd();
	For(i,1,n){
		cin>>a[i]>>b[i]>>v[i];
		s+=v[i];//记录权值总和 
		c[++tot]=a[i],c[++tot]=b[i];// 
	}sort(c+1,c+tot+1);
	For(i,1,n){
		a[i] = lower_bound(c+1,c+tot+1,a[i])-c;
		b[i] = lower_bound(c+1,c+tot+1,b[i])-c;
		g[b[i]].emplace_back(a[i],v[i]);//记录区间,定右端点 
	}
	For(i,1,n*2){//离散化后最多有2n个点 
		for(auto p:g[i]) h[p.x].emplace_back(p.y);//左端点的贡献 
		int sum = 0, t = 0;
		while(q.size()) q.pop();
		
		Rof(j,i,1){
			for(auto k:h[j]){//枚举区间 
				if(++t<=m) q.emplace(-k),sum+=k;//如果没超过了k个 
				else if(-q.top()<k){//否则将贡献小的弹出 
					sum+=q.top();
					sum+=k;
					q.pop();
					q.emplace(-k);
				}f[i] = max(f[i], f[j-1]+sum);
			}
		}
	}cout<<s-f[2*n]<<'\n';
}

bool ED;
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
//	freopen("ex_variance2.in","r",stdin);
	freopen("variance.in","r",stdin);
	freopen("variance.out","w",stdout);
	int T = 1, Tim = clock();
	while(T--) solve();
	return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
} 

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录