Wi-Fi(线段树+dp)

思路

  • 一道dp题,就是转移方程需要思考,第一种情况肯定是直接连wife,第二种情况就是放置一个wife,第二种情况的转移方程为:dp[i]=min(dp[i],dp[j]+i-k),其中如果i这个位置被覆盖了,那么是在i-k的位置放置路由器,所以花费i-k,dp[j]是i-2*k到i位置的最小的dp值。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MXN = 2e5+5;
const int MXLOG = 18;
int lz[MXN<<2],T[MXN<<2];

inline void pushUp(int rt){
    T[rt]=min(T[rt<<1],T[rt<<1|1]);
}

void pushDown(int rt){
    if(lz[rt]!=LLONG_MAX/10){
        lz[rt<<1]=min(lz[rt],lz[rt<<1]);
        lz[rt<<1|1]=min(lz[rt],lz[rt<<1|1]);
        T[rt<<1]=min(lz[rt],T[rt<<1]);
        T[rt<<1|1]=min(lz[rt],T[rt<<1|1]);
        lz[rt]=LLONG_MAX/10;
    }
}

void build(int l,int r,int rt){
    lz[rt]=LLONG_MAX/10;
    if(l==r){
        T[rt]=LLONG_MAX/10;
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushUp(rt);
}

void update(int L,int R,int c,int l,int r,int rt){
    if(l>=L&&r<=R){
        lz[rt]=min(lz[rt],c);
        T[rt]=min(T[rt],c);
        return;
    }
    pushDown(rt);
    int m=(l+r)>>1;
    if(m>=L) update(L,R,c,l,m,rt<<1);
    if(m<R)  update(L,R,c,m+1,r,rt<<1|1);
    pushUp(rt);
}

int query(int L,int R,int l,int r,int rt){
    if(l>=L&&r<=R)
        return T[rt];
    pushDown(rt);
    int m=(l+r)>>1;
    int re=LLONG_MAX/10;
    if(m>=L) re=min(re,query(L,R,l,m,rt<<1));
    if(m<R)  re=min(re,query(L,R,m+1,r,rt<<1|1));
    return re;
}
int to[MXN];
int midPos[MXN];
signed main(){
    int n,k;cin>>n>>k;
    string s;cin>>s;
    build(1,n+1,1);
    for(int i=1;i<=n;i++) to[i]=n+1;
    for(int i=n-1;i>=0;i--){
        if(s[i]=='1'){
            int ll=max(1LL,i+1-k),rr=min(n,i+1+k);
            if(ll<=to[rr]) to[rr]=ll,midPos[rr]=i+1;
        }
    }
    update(n+1,n+1,0,1,n+1,1);
    for(int i=n;i>=1;i--){
        int t1=query(i,i,1,n+1,1),t2=query(i+1,i+1,1,n+1,1)+i;
        update(i,i,min(t1,t2),1,n+1,1);
        if(to[i]<i) update(to[i],i,midPos[i]+t2-i,1,n+1,1);
    }
    cout<<query(1,1,1,n+1,1);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值