Codeforces Round #587 (Div. 3)_F_DP线段树优化

题目链接:https://codeforces.com/contest/1216/problem/F

解题思路:

在这里插入图片描述
代码:

//f[i][0]:对于第i个位置我们不放路由器,并且让1 - i所有为止都连接到网络
//f[i][1]:对于第i个为止我们要放路由器,并且让1 - i所有位置都连接道网络 
//
//f[i][0] = min(f[i - 1][0] + i, f[i - k --- i - 1][1]);  1:前面没有放路由器,直接连接到网络  2:直接噌前面的路由器 
//f[i][1] = min(f[i - k --- i - 1][0], f[i - k * 2 - 1 --- i - 1][1]) + i;     1:前面没有放路由器   2:前面放了路由器 
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
typedef long long LL;
 
const int maxn = 2e5 + 10;
const LL inf = 5e10;
 
char str[maxn];
LL f[maxn][3];
struct SegmentTree { int l, r; LL min0, min1; }t[maxn * 20];
 
inline void build(int s, int l, int r) {
	t[s].l = l, t[s].r = r;
	t[s].min1 = t[s].min0 = inf;
//	printf("%lld\n", t[s].min1);
	if(l == r) return;
 
	int mid = l + r >> 1;
	build(s * 2, l, mid);
	build(s * 2 + 1, mid + 1, r);
}
 
inline void insert1(int s, int l, int r, LL x) {
	if(l <= t[s].l && r >= t[s].r) {
		t[s].min1 = x;
		return;
	}
 
	int mid = (t[s].l + t[s].r) >> 1;
	if(l <= mid) insert1(s * 2, l, r, x);
	else insert1(s * 2 + 1, l, r, x);
 
	t[s].min1 = min(t[s * 2].min1, t[s * 2 + 1].min1);
}
 
inline void insert0(int s, int l, int r, LL x) {
	if(l <= t[s].l && r >= t[s].r) {
		t[s].min0 = x;
		return;
	}
	
	int mid = (t[s].l + t[s].r) >> 1;
	if(l <= mid) insert0(s * 2, l, r, x);
	else insert0(s * 2 + 1, l, r, x);
	
	t[s].min0 = min(t[s * 2].min0, t[s * 2 + 1].min0);
}
 
inline LL query0(int s, int l, int r) {
	if(l > r) return inf; 
	if(l <= t[s].l && r >= t[s].r) {
		return t[s].min0;
	}
	
	int mid = t[s].l + t[s].r >> 1;
	LL tmp = inf;
	if(l <= mid) tmp = min(tmp, query0(s * 2, l, r));
	if(r > mid) tmp = min(tmp, query0(s * 2 + 1, l, r));
	
	return tmp;
}
 
inline LL query1(int s, int l, int r) {
	if(l > r) return inf;
	if(l <= t[s].l && r >= t[s].r) {
		return t[s].min1;
	}
	
	int mid = t[s].l + t[s].r >> 1;
	LL tmp = inf;
	if(l <= mid) tmp = min(tmp, query1(s * 2, l, r));
	if(r > mid) tmp = min(tmp, query1(s * 2 + 1, l, r));
 
	return tmp;
}
 
int main(void) {
//	freopen("in.txt", "r", stdin);
	int n, k; scanf("%d%d", &n, &k);
	scanf("%s", str + 1);
	
	build(1, 0, n);
	
	for(int i = 0; i <= n; i ++)
		for(int j = 0; j <= 1; j ++)
			f[i][j] = inf;
//	printf("%lld\n", f[2][1]);
	
	f[0][0] = 0; insert0(1, 0, 0, 0);
	for(int i = 1; i <= n; i ++) {
		f[i][0] = min(f[i - 1][0] + i, query1(1, max(0, i - k), i - 1));
		insert0(1, i, i, f[i][0]);
		if(str[i] == '1') {
			f[i][1] = min(query0(1, max(i - k - 1, 0), i - 1), query1(1, max(0, i - k * 2 - 1), max(i - 1, 0))) + i;
			insert1(1, i, i, f[i][1]);
		}
			
//		printf("%d %d %d\n", i, f[i][0], f[i][1]);
	}
 
	printf("%lld\n", min(f[n][1], f[n][0]));
 
	return 0;
}

总结:这道题目我花了花几天才做出来,导致我花这么多天的原因是inf的类型用成了int,应该用long long 的,因为5e10超过了int范围;我都服了我自己了。。。
以后在debug的时候应该先检查全局变量的申明,尤其是需要检出是否数据类型是否出错;
状态不但可以从前一个转移过来,同时还可以从前面的任意一个状态转移过来。

发布了136 篇原创文章 · 获赞 0 · 访问量 2989

猜你喜欢

转载自blog.csdn.net/weixin_42596275/article/details/102377471