Codeforces Round #587 (Div. 3) F. Wi-Fi(DP)

题意:

给你n个点,一个覆盖范围k,编号[1,n],点i与网络直接连接的代价是i,如果这个点是关键点,那么让它与网络直接连接后它可以让编号在[i-k,i+k]的点与网络间接连接,求让全部点和网络连接的最小代价。

题解:

这题感觉蛮难想,一开始往贪心想,不太好贪,再想DP,又觉得前后都会影响,想不清楚。这里其实还是DP。
用dp[i]表示把[1,i]的点全部连接需要的最小花费,那么对于dp[i],有两种情况:

  1. 它花费i直接与网络相连
  2. 它通过它前面的点间接与网络相连

情况1直接就是 d p [ i ] = d p [ i − 1 ] + i dp[i] = dp[i-1]+i dp[i]=dp[i1]+i
对于情况2,应该是 d p [ i ] = m i n ( v a l [ j ] ) dp[i] = min(val[j]) dp[i]=min(val[j]),j代表[i-k,i-1]中的关键点,val[j]是[1,j]都连起来且j直接和网络相连的最小花费。
那么可以看出 v a l [ j ] = m i n ( d p [ i ] ) + j val[j]=min(dp[i])+j val[j]=min(dp[i])+j,其中i的范围是[j-k-1,j-1]。
那么现在我们就可以维护dp数组和val数组,然后互相推了。这里题解用multiset去维护可以用的dp和val值,看着挺方便的。
如果我自己推出这个式子我应该会打两个线段树

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 2e5 + 50;
int n, k;
char s[maxn];
multiset<ll> s1, s2;//s1是当前可以触摸到的位置的dp值,s2可以更新当前点的dp值
vector<ll> del[maxn];//当前点开始就不能使用的s2中的值
ll dp[maxn];//dp[i]表示把[1,i]连接起来需要的最小花费
int main()
{
    cin>>n>>k;
    scanf("%s", s+1);
    dp[0] = 0;
    s1.insert(dp[0]);
    for(int i = 1; i <= n; ++i){
        dp[i] = dp[i-1] + i;//先直接连接
        if(i-k-2 >= 0) s1.erase( s1.find(dp[i-k-2]) );
        for(int j = 0; j < del[i].size(); ++j) s2.erase( s2.find(del[i][j]) );//维护s1和s2保证它们当前存储的值可用

        if( s2.size() ) dp[i] = min(dp[i], *s2.begin());
        if(s[i] == '1'){
            ll val;//当前点作为路由器连接所需要花费的最小费用
            if(s1.size()) val = *s1.begin() + i;
            else val = i;
            dp[i] = min(dp[i], val);

            s2.insert(val);
            if(i+k+1 <= n) del[i+k+1].push_back(val);//一直到i+k为止都可以使用这个val去更新dp
        }
        s1.insert(dp[i]);
    }
    cout<<dp[n]<<endl;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值