牛客小白月赛 B-Gaming

B-Gaming_牛客小白月赛54 (nowcoder.com)

题意:

有n个区间,你每在数轴上覆盖一个区间,积分就加s[i],问你不让区间全部被覆盖的最大积分是多少

思路:

还原一下当时写这道题的思路:

最大,那就考虑贪心,先假设所有区间全部覆盖了(贪心极端情况),然后去看拿走哪个区间可以让一个位置空出来。哇了一发,后来发现可能要去掉的不只一个区间,我们要去掉的是最少覆盖的位置上面包含的所有区间,所以我就想维护包含这个最小覆盖点的所有区间,也就是这个区间内的最小覆盖值,维护区间最小我就糊上了线段树,把包含最少覆盖点的区间都去掉,剩下的区间积分加起来就是答案了,然后就哇了。。。。

我不懂为什么会哇。。。

正解应该是:

要使区间没有完全覆盖,我们要至少留出一个空位
至于留出哪个空位我们不知道
因此我们去枚举这个空位
把覆盖这个空位的区间的积分贡献都减掉
那么总积分减去这个积分贡献就是答案

这个空位的积分贡献用区间++就可以,也就是差分

看起来好像差不多,但是我的做法显然烦了很多,也很易错

我的做法维护了一些本来就不需要维护的一些东西,比如一个空位到底是由哪些区间覆盖的,这根本就不需要维护,我们需要维护的只是这个空位上有多少积分,因此只需要差分就可以了!

Code:

/*
要使区间没有完全覆盖,我们要至少留出一个空位
至于留出哪个空位我们不知道
因此我们去枚举这个空位
把覆盖这个空位的区间的积分贡献都减掉
那么总积分减去这个积分贡献就是答案
*/
#include 
using namespace std;
const int mxn=1e6+10;
#define int long long
int n,m,sum=0;
int l[mxn],r[mxn],s[mxn],d[mxn],mi=1e18;
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&l[i],&r[i],&s[i]);
        d[l[i]]+=s[i];d[r[i]+1]-=s[i];
        sum+=s[i];
    }
    for(int i=1;i<=m;i++){
        d[i]+=d[i-1];
        mi=min(mi,d[i]);
    }
    printf("%lld\n",sum-mi);
}

总结:

1.只维护需要维护的内容!很多时候做法比别人烦就是因为维护了一些根本不需要维护的东西,因此以后做题的时候发现要维护一些数据的时候要提醒自己这个数据真的需要维护吗?和答案无关就不要维护!

你可能感兴趣的:(牛客系列赛,枚举,贪心算法,算法)