Kpop Music Party 【贪心】

本文详细解析了ZOJ-3941题目的解题思路,通过贪心算法结合枚举策略,讨论了如何在给定条件下最大化收益。作者分享了使用递归和二进制枚举的方法,并提供了完整的C++代码实现,强调了在处理区间问题时的特殊技巧。

题目链接:https://cn.vjudge.net/problem/ZOJ-3941

 

这道题目最先想到的是贪心,从最左边开始,依次选择长度k的区间,不相交,这样是最大的。但是这样贪心完之后发现m还有剩余,

发现每个区间的最后一点也可以选,同样可以有增益效果,但是回头再去选,会打乱一开始的贪心,所以在贪心的时候就枚举每个区间

最后一个点要不要选,最后也就2的10次方种可能
--------------------- 
作者:Dacc123 
来源:优快云 
原文:https://blog.youkuaiyun.com/dacc123/article/details/51279068 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

如上:

可以使用递归或者二进制枚举写,递归写起来简单一些。需要特别注意向上取整的过程。

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a);i <= (b); i++)
#define mp make_pair
#define pb push_back
#define ll long long
#define pli pair<long long,int>
#define all(x) (x).begin(),(x).end()
using namespace std;
const int N = 20;
struct node{
    int l, r;
    node(){}
    node(int a,int b) {
        l = a;
        r = b;
    }
    bool operator <(node b) const{
        if(l != b.l) return l<b.l;
        else return r<b.r;
    }
}s[N],s2[N];
int n,m,k,ans,tot;
void check(int x) {
    int sum = 0;
    int rem = m;
    bitset<10> sta(x);
    int pos = 0;
    rep(i, 1, tot) {
        if(rem==0) {
            ans = max(ans,sum);
            return;
        }
        int l = s[i].l;
        int r = s[i].r;
        if(pos>l) l = pos;
        int num = (r-l+1+k-1)/k;//这里很关键,因为l可能大于r的原因,所以不能用(r-l+1)%k来判断
        if(rem>num) {
            rem -= num;
            sum += num*k;
            int rr = l+num*k-1;
            if(sta[i-1]) {
                rem--;
                pos = r+k;
                sum += k;
                sum -= (rr-r+1);
            }else pos = rr+1;
        }
        else {
            sum += rem*k;
            ans = max(ans,sum);
            return ;
        }
    }
    ans = max(ans,sum);
}
int main() {
    //freopen("a.txt","r",stdin);
    ios::sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--) {
        cin>>n>>k>>m;
        rep(i, 1, n) cin>>s2[i].l>>s2[i].r;
        sort(s2+1,s2+n+1);
        tot = 0;
        node now=s2[1];
        rep(i, 2, n) {
            if(s2[i].l<=now.r)
                now.r = max(now.r,s2[i].r);
            else {
                s[++tot] = now;
                now = s2[i];
            }
        }
        s[++tot] = now;
        ans = 0;

        int last  = 1;
        rep(i, 1, tot) last *= 2;
        rep(i, 0, last-1) check(i);

        cout<<ans<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值