题目链接: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;
}