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

题目链接【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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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;
}

 

你可能感兴趣的:(线段树,DP动态规划,数据结构)