Codeforces Round #587 (Div. 3) F Wi-Fi(线段树+dp)

题意:给定一个字符串s 现在让你用最小的花费 覆盖所有区间

思路:dp[i]表示前i个全覆盖以后的花费 如果是0 我们只能直接加上当前位置的权值 否则 我们可以区间询问一下最小值 然后更新

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const int N = 2e5+7;
typedef long long ll;
const ll mod = 998244353;
using namespace std;
ll dp[N];
ll a[N],sum[N];
struct tree{
    int l,r;
    ll v;
    int po;
}t[N<<4];
int nico=0;
void build(int p,int l,int r){
    t[p].l=l; t[p].r=r; t[p].v=inf;
    if(l==r){
        t[p].po=l;
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}
void update(int p,int x,ll v){
    if(t[p].l==t[p].r){
        t[p].v=v;
        return ;
    }
    int mid=(t[p].l+t[p].r)>>1;
    if(x<=mid) update(p<<1,x,v);
    else update(p<<1|1,x,v);
    if(t[p<<1].v<t[p<<1|1].v){
        t[p].v=t[p<<1].v;
        t[p].po=t[p<<1].po;
    }else{
        t[p].v=t[p<<1|1].v;
        t[p].po=t[p<<1|1].po;
    }
}
tree query(int p,int l,int r){
    if(l<=t[p].l&&t[p].r<=r){
        return t[p];
    }
    int mid=(t[p].l+t[p].r)>>1;
    tree res1,res2;
    if(l>mid){
        return query(p<<1|1,l,r);
    }else if(r<=mid){
        return query(p<<1,l,r);
    }else{
        res1=query(p<<1,l,r);
        res2=query(p<<1|1,l,r);
        if(res1.v<res2.v){
            return res1;
        }else{
            return res2;
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n,k; cin>>n>>k;
    string s; cin>>s;
    build(1,0,n);
    update(1,0,0);
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+i;
    }
    int mi=inf;
    for(int i=n-1;i>=0;i--){
        if(s[i]==‘1‘&&i!=n-1){
            s[min(i+k,n-1)]=‘1‘;
            s[i]=‘0‘;
            if(i+k>=n-1){
                mi=min(mi,i)+1;
            }
        }
    }
    if(s[n-1]==‘1‘&&mi==inf){
        mi=n;
    }
//    cout<<s<<endl;
    for(int i=1;i<=n;i++){
        if(s[i-1]==‘1‘){
            if(i==n){
                tree res=query(1,max(mi-k-1,0),i-1);
                dp[i]=res.v+mi;
            //    dp[i][0]=min(dp[i-1][0],dp[i-1][1])+mi;
            }else{
                tree res=query(1,max(i-2*k-1,0),i-1);
                dp[i]=res.v+i-k;
            //    dp[i][0]=min(dp[i-1][0],dp[i-1][1])+i-k;
            }
        }else{
            dp[i]=dp[i-1]+i;
        //    dp[i][0]=inf;
        }
        update(1,i,dp[i]);
    }
    cout<<dp[n]<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/wmj6/p/11568601.html

时间: 2024-08-29 03:50:26

Codeforces Round #587 (Div. 3) F Wi-Fi(线段树+dp)的相关文章

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery 题意: 给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大. 题解: 考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp, 考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a

Codeforces Round #424 (Div. 2) E. Cards Sorting(线段树)

题目链接:Codeforces Round #424 (Div. 2) E. Cards Sorting 题意: 将n个数放进一个队列,每次检查队首,看看是不是队列中最小的数,如果是就扔掉,如果不是就放到队尾. 这样直到队列为空,为需要操作多少次. 题解: 考虑用两个指针模拟,最开始now指针指向第一个数,然后nxt指针指向下一个将要被删除的数. 然后我们要算出这里需要移动多少步,然后删掉这个数,一直重复操作,直到将全部的数删完. nxt指针可以用set来维护,now指针可以用并查集来维护. 计

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c

Codeforces Round #603 (Div. 2) E. Editor(线段树)

链接: https://codeforces.com/contest/1263/problem/E 题意: The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which point

[Codeforces Round #296 div2 D] Clique Problem 【线段树+DP】

题目链接:CF - R296 - d2 - D 题目大意 一个特殊的图,一些数轴上的点,每个点有一个坐标 X,有一个权值 W,两点 (i, j) 之间有边当且仅当 |Xi - Xj| >= Wi + Wj. 求这个图的最大团. 图的点数 n <= 10^5. 题目分析 两点之间右边满足 Xj - Xi >= Wi + Wj (Xi < Xj)       ==>     Xj  - Wj >= Xi + Wi (Xi < Xj) 按照坐标 x 从小到大将点排序.用

Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并

D. Developing Game Pavel is going to make a game of his dream. However, he knows that he can't make it on his own so he founded a development company and hired n workers of staff. Now he wants to pick n workers from the staff who will be directly res

Codeforces Round #275 Div.1 B Interesting Array --线段树

题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的按位与和至少为多少. 更新时,如果val的pos位为1,那么整个区间的按位与和pos位也应该为1,否则与出来就不对了.(这是本题解题的核心) 那么此时更新 sum[rt] |= val 即可.然后再check一遍看是否满足所有条件即可. 代码: #include <iostream> #inclu

Codeforces Round #486 (Div. 3) F. Rain and Umbrellas

Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/contest/988/problem/E Description Polycarp lives on a coordinate line at the point x=0. He goes to his friend that lives at the point x=a. Polycarp can