Wi-Fi【Codeforces Round #587 (Div. 3)】【线段树优化dp】

110 篇文章 0 订阅
106 篇文章 0 订阅

题目链接【Codeforces 1216F】


You work as a system administrator in a dormitory, which has ?n rooms one after another along a straight hallway. Rooms are numbered from 11 to ?n.

You have to connect all ?n rooms to the Internet.

You can connect each room to the Internet directly, the cost of such connection for the ?i-th room is ?i coins.

Some rooms also have a spot for a router. The cost of placing a router in the ?i-th room is also ?i coins. You cannot place a router in a room which does not have a spot for it. When you place a router in the room ?i, you connect all rooms with the numbers from ???(1, ?−?)max(1, i−k) to ???(?, ?+?)min(n, i+k) inclusive to the Internet, where ?k is the range of router. The value of ?k is the same for all routers.

Calculate the minimum total cost of connecting all ?n rooms to the Internet. You can assume that the number of rooms which have a spot for a router is not greater than the number of routers you have.

Input

The first line of the input contains two integers ?n and ?k (1≤?,?≤2⋅1051≤n,k≤2⋅105) — the number of rooms and the range of each router.

The second line of the input contains one string ?s of length ?n, consisting only of zeros and ones. If the ?i-th character of the string equals to '1' then there is a spot for a router in the ?i-th room. If the ?i-th character of the string equals to '0' then you cannot place a router in the ?i-th room.

Output

Print one integer — the minimum total cost of connecting all ?n rooms to the Internet.


  确实,比赛的时候没想到嘤嘤嘤!这都不重要!!!关键是…… 哼!

  首先,我们要想,对于每个点,有的点是可以用“1”的(也就是放个路由器),有的点是可以直接使用i价值链接上网,或者收益于其他的路由器的。

  那么,我们首先考虑没有放置路由器空间的点,它是不是可以看成前面有路由器的点的受益者,或者是直接有前一个点的价值加上i来满足条件。

  其次,看可以放置路由器的点,它的价值应该如何去确定呢?可以找到前面的[i - K, i - 1]区间的为不使用路由器的最小值,然后再比较[i - K -1, i - 1]区间内的使用路由器的最小值,不断的这样递推下去即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, K;
ll  a[2][maxN<<2], dp[maxN][2];
char op[maxN];
void buildTree(ll *tree, int rt, int l, int r)
{
    tree[rt] = INF;
    if(l == r) return;
    int mid = HalF;
    buildTree(tree, Lson); buildTree(tree, Rson);
}
ll query(ll *tree, int rt, int l, int r, int ql, int qr)
{
    if(ql <= l && qr >= r) return tree[rt];
    int mid = HalF;
    if(qr <= mid) return query(tree, QL);
    else if(ql > mid) return query(tree, QR);
    else return min(query(tree, QL), query(tree, QR));
}
inline void pushup(ll *tree, int rt) { tree[rt] = min(tree[lsn], tree[rsn]); }
void update(ll *tree, int rt, int l, int r, int qx, ll val)
{
    if(l == r)
    {
        tree[rt] = val;
        return;
    }
    int mid = HalF;
    if(qx <= mid) update(tree, Lson, qx, val);
    else update(tree, Rson, qx, val);
    pushup(tree, rt);
}
int main()
{
    scanf("%d%d", &N, &K);
    scanf("%s", op + 1);
    buildTree(a[0], 1, 1, N);
    buildTree(a[1], 1, 1, N);
    dp[N][1] = INF; dp[0][0] = 0;
    for(int i=1; i<=N; i++)
    {
        if(i > 1) dp[i][0] = min(dp[i-1][0] + i, query(a[1], 1, 1, N, i - K, i - 1));
        else dp[i][0] = i;
        update(a[0], 1, 1, N, i, dp[i][0]);
        if(op[i] == '1')
        {
            if(i - K <= 1) dp[i][1] = i;
            else if(i > 1) dp[i][1] = min(query(a[1], 1, 1, N, i - K - 1, i - 1), query(a[0], 1, 1, N, i - K - 1, i - 1)) + i;
            update(a[1], 1, 1, N, i, dp[i][1]);
        }
    }
    printf("%lld\n", min(dp[N][0], dp[N][1]));
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值