题目链接: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的时候应该先检查全局变量的申明,尤其是需要检出是否数据类型是否出错;
状态不但可以从前一个转移过来,同时还可以从前面的任意一个状态转移过来。