贪心。要求每个区间至少有k个点覆盖,如果区间长度不足k则全部有点覆盖。
根据区间右端点从小到大排序,如果右端点相同则根据左从小到大排序。对于每个区间选取右边k个端点。这里有个问题就是,如果该段区间已经选过一部分点了,那需要统计一下已经选过多少点,我这里用了最笨的办法,直接数(由于区间有负数,所以都加了10005来消掉负数),这样再把剩下的点选够即可。
这样最坏的情况是1000*20000,居然没超时。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
#define ll long long
#define INF 200000000
#define VAL 10005
using namespace std;
struct Segment
{
int L,R;
Segment(int a,int b):L(a),R(b) {}
bool operator < (Segment p) const
{
if(R==p.R) return L<p.L;
return R<p.R;
}
};
vector<Segment> vec;
bool vis[VAL*2];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int k,n;
scanf("%d%d",&k,&n);
memset(vis,0,sizeof(vis));
vec.clear();
int minn=INF,maxn=0;
for(int i=0; i<n; ++i)
{
int l,r;
scanf("%d%d",&l,&r);
if(l>r) swap(l,r);
l+=VAL;
r+=VAL;
minn=min(l,minn);
maxn=max(r,maxn);
vec.push_back(Segment(l,r));
}
sort(vec.begin(),vec.end());
for(int i=0; i<vec.size(); ++i)
{
int l=vec[i].L,r=vec[i].R;
int c=0;
if(i==0||vec[i-1].R<vec[i].L) c=0;
else
{
for(int j=l; j<=r; ++j)
if(vis[j]) c++;
}
if(c<k)
{
for(int j=r; j>=l&&c<k; --j)
if(!vis[j])
{
vis[j]=true;
c++;
}
}
}
vector<int> ans;
for(int i=minn; i<=maxn; ++i)
if(vis[i]) ans.push_back(i-VAL);
printf("%d\n",ans.size());
for(int i=0; i<ans.size(); ++i)
printf("%d\n",ans[i]);
if(T) printf("\n");
}
return 0;
}