[Codeforces 115E]Linear Kingdom Races

题目大意:

有n块地,初始是荒地。你可以把某些荒地开垦(需要花费相应的价值\(a_i\)(正整数)),然后这些荒地就可以种田。

现在有m年,每年要在l到r区间内种田,获得p(正整数)的价值(必须保证l~r都已经开荒,否则不能种田)。

问最大收益。

解题思路:

DP。

设F[i][j]表示前i块地,最后有连续的j块地已开荒的最大收益。

则\(F[i+1][0]=max\{F[i][j]\}\)。不开荒,则中间断了,所以连续的值只有0了。

F[i+1][j+1]=F[i][j]-a[i]+v。开荒,则花费价值,而且可能会有一些年份可以种田了,则加上这些收益(v是加上后能多出来的种田收益)。

于是我们要记录下以每个值作为右端点的种田个数。

答案即为\(max\{F[n][i]\}\)

发现这是个时空复杂度都是\(O(n^2)\)的东西。

首先第一维可以滚掉。

然后,考虑每个\(a[i]\)都要在整个区间减一遍,而每年种田的价值也会对一段区间有影响。

所以考虑线段树优化。

线段树每个节点记录这个节点下面的儿子的状态的最优值。

然后发现枚举i时,之前的状态都要向右偏移一格,非常麻烦。

倒着建状态就好辣~喵~o( =∩ω∩= )m

C++ Code:

#include
using namespace std;
using LoveLive=long long;
const int N=2e5+5;
LoveLive d[N*4],tag[N*4],a[N];
int n,m,L,R;
LoveLive add;
vector>v[N];
inline LoveLive max(LoveLive&a,LoveLive&b){return a>b?a:b;}
inline void pd(int&o){
    if(tag[o]){
        int l=o<<1,r=l|1;
        d[l]+=tag[o];
        d[r]+=tag[o];
        tag[l]+=tag[o];
        tag[r]+=tag[o];
        tag[o]=0;
    }
}
void add_1(int l,int r,int o){
    if(l==r)d[o]+=add;else{
        pd(o);
        int mid=l+r>>1;
        if(L<=mid)add_1(l,mid,o<<1);else
        add_1(mid+1,r,o<<1|1);
        d[o]=max(d[o<<1],d[o<<1|1]);
    }
}
void add_lot(int l,int r,int o){
    if(L<=l&&r<=R)d[o]+=add,tag[o]+=add;else{
        int mid=l+r>>1;
        pd(o);
        if(L<=mid)add_lot(l,mid,o<<1);
        if(mid>n>>m;
    for(int i=1;i<=n;++i)cin>>a[i];
    for(int i=1,l,r;i<=m;++i){
        cin>>l>>r>>add;
        v[r].push_back(make_pair(l,add));
    }
    for(int i=1;i<=n;++i){
        L=n-i,add=d[1];
        add_1(0,n,1);
        ++L,R=n,add=-a[i];
        add_lot(0,n,1);
        for(auto it:v[i]){
            L=n-it.first+1,R=n,add=it.second;
            add_lot(0,n,1);
        }
    }
    cout<

 

转载于:https://www.cnblogs.com/Mrsrz/p/9385612.html

你可能感兴趣的:(c/c++)