区间选点
给定 N N N 个闭区间 [ a i , b i ] [a_{i},b_{i}] [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点,输出选择的点的最小数量(位于区间端点上的点也算作区间内)
思路:
将每个区间按照右端点从小到大进行排序,从前往后枚举区间,最右边界值ed初始化为无穷小,之后和区间左端点比较,不断更新即可
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range{
int l, r;
bool operator< (const Range &W)const{
return r < W.r;//按r从小到大排序
}
}range[N];
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d%d", &range[i].l, &range[i].r);
sort(range, range + n);
int res = 0, ed = -2e9;
for (int i = 0; i < n; i ++ )
if (range[i].l > ed){
res ++ ;
ed = range[i].r;
}
printf("%d\n", res);
return 0;
}
活动安排
传送门
思路:
和上一题类似,唯一的不同就是代码部分if (range[i].l > ed)
要改变为if (range[i].l >= ed)
,因为活动是左闭右开的,左右端点可以重合,代表2个活动可以依次发生,不像上一题,区间上点如果重合,则会亏一些
种树
传送门
思路:
和上一题类似,一样的排序,如果当前区间的树不够的话,就在区间右端点种树
WA的代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=3e4+5;
bool b[N];
struct tree{
int l,r,num;
bool operator <(tree const &t1)const{
return r<t1.r;
}
}a[N];
int n,m;
int main(){
ll res=0;
cin>>n>>m;
f(i,0,m){
scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].num);
}
sort(a,a+m);
f(i,0,m){
int cnt=0;
ff(j,a[i].l,a[i].r){
if(b[j])cnt++;
}
if(cnt>=a[i].num)continue;
for(int j=a[i].r,p=0;p<(a[i].num-cnt);j--,p++){
b[j]=1;res++;
}
}
cout<<res<<endl;
return 0;
}
之后发现WA的原因是在重复地方种树了,因为虽然是右区间从小到大排的序,但是左区间不确定,所以说区间树的分布可能是中间有很多树,但区间的两边没有树,所以要设一个标记数组,重复的树不再标记,可以看下面的图:
AC代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=3e4+5;
bool b[N];
struct tree{
int l,r,num;
bool operator <(tree const &t1)const{
return r<t1.r;
}
}a[N];
int n,m;
int main(){
ll res=0;
cin>>n>>m;
f(i,0,m){
scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].num);
}
sort(a,a+m);
f(i,0,m){
int cnt=0;
ff(j,a[i].l,a[i].r){
if(b[j])cnt++;
}
if(cnt>=a[i].num)continue;
for(int j=a[i].r;j>=a[i].l;j--){
if(!b[j]){
b[j]=1;
res++;
cnt++;
if(cnt>=a[i].num)break;
}
}
}
cout<<res<<endl;
return 0;
}
喷水装置
传送门
思路:
将区间按左端点从小到大排序,从左向右依次处理每个区间。每次选择覆盖点st的区间中右端点坐标最大的一个(设为ed),并将st更新为ed,直到浇灌完草坪,或喷头用完为止
代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=2e4+5;
struct st{
double l,r;
bool operator<(st const &t1)const{
return l<t1.l;
}
}a[N];
int t;
int main(){
cin>>t;
while(t--){
int n;
double L,W;
scanf("%d %lf %lf",&n,&L,&W);
W/=2;
double p,r;
int cnt=0;
f(i,0,n){
scanf("%lf %lf",&p,&r);
//取等的时候就包含那一个点,可以要。。
if(r<W)continue;
double d=sqrt(r*r-W*W);
a[cnt].l=p-d,a[cnt].r=p+d;
cnt++;
}
sort(a,a+cnt);
int flag=0,pos=0;
double ed=0;
int res=0;
while(ed < L){
res++;
//该写成double的别写成int
double st=ed;
for(; a[pos].l <= st && pos < cnt; pos++){
if(a[pos].r>ed)ed=a[pos].r;
}
if(ed>=L)break;
if(st==ed){
flag=1;
cout<<-1<<endl;
break;
}
}
if(!flag)cout<<res<<endl;
}
return 0;
}
加工生产调度
样例解释:
推荐一篇题解:【贪心】加工生产调度(双机调度贪心问题)
WA代码:
#include<bits/stdc++.h>
typedef long long ll;
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
struct node{
int id,a,b,flag;
}item[10010];
bool cmp(node x,node y){
//整体分为2部分:先bi较大(ai<bi),再ai较大(ai>bi)
if(x.flag!=y.flag)
return x.flag<y.flag;
//bi较大的里面,按ai较小排序
if(x.flag==0)
return x.a<y.a;
//ai较大的里面,按bi较大排序
else return x.b>y.b;
}
int main(){
int n; scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&item[i].a);
for(int i=0;i<n;i++)scanf("%d",&item[i].b);
for(int i=0;i<n;i++){
item[i].id=i+1;
item[i].flag=(item[i].a<item[i].b?0:1);
}
sort(item,item+n,cmp);
ll A=0,B=0;
for(int i=0;i<n;i++){
A+=item[i].a;
B=max(A,B)+item[i].b;
}
printf("%lld\n",B);
for(int i=0;i<n;i++){
if(i!=n-1)cout<<item[i].id<<" ";
else cout<<item[i].id<<endl;
}
}
不知道为啥QAQ,感觉很疑惑
推荐另一篇题解:【结论】加工生产调度
又得到了WA代码:
#include <bits/stdc++.h>
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
//
const int N=10005;
int n,sum1=0,sum2=0,l=0,r;
int res[N],a[N],b[N];
struct st{
int x,id;
bool operator <(st const &t1)const{
return x<t1.x;
}
}num[N];
int main(){
scanf("%d",&n);
ff(i,1,n) cin>>a[i];
ff(i,1,n) cin>>b[i];
ff(i,1,n)
num[i].id=i,num[i].x=min(a[i],b[i]);
sort(num,num+n+1);
r=n+1;
ff(i,1,n){
//对应博客里m==a,放前面
if(num[i].x==a[num[i].id]) res[++l]=num[i].id;
//对应博客里m==b,放后面
else res[--r]=num[i].id;
}
ff(i,1,n){
sum1+=a[res[i]];
sum2=max(sum1,sum2)+b[res[i]];
}
cout<<sum2<<"\n";
ff(i,1,n)
cout << res[i] << " ";
return 0;
}
AC代码:
把结构体sort排序改为手动排序:
for(int i=1;i<=n-1;i++)
for(int j=i+1;j<=n;j++)
if(num[i].x>num[j].x){
swap(num[i].x,num[j].x);
swap(num[i].id,num[j].id);
}
稍微改一下结构体重载比较函数的代码,发现分数高了!
struct st{
int x,id;
bool operator <(st const &t1)const{
return x<=t1.x;
}
}num[N];
于是猜测题目出锅了(它缺少special judge哇 )