【反悔贪心】
【反悔贪心】
排序+枚举一个点+堆维护另一个点
建筑抢修
https://ac.nowcoder.com/acm/problem/20154
思路
按照截止时间从小到大排序,并遍历截止时间
表示在当前的截止时间内,最多能修多少个建筑
如果修建筑所花时间超过了当前的截止时间->把要花最多时间的去掉->大根堆维护
代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=150010;
int n;
struct node{
int t1,t2;
}a[N];
bool cmp(node x,node y){
if(x.t2!=y.t2) return x.t2<y.t2;
return x.t1<y.t1;
}
priority_queue<int> q;
//注意加greater是小根堆 默认大根堆
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].t1>>a[i].t2;
sort(a+1,a+1+n,cmp);
ll ans=0;
int cnt=0;
for(int i=1;i<=n;i++){
q.push(a[i].t1);
ans+=a[i].t1;
cnt++;
while(ans>a[i].t2 && q.size()){
int t=q.top();
q.pop();
ans-=t;
cnt--;
}
}
cout<<cnt;
return 0;
}
井然有序之窗
https://ac.nowcoder.com/acm/contest/95323/H
思路
以左端点排序并遍历,用小根堆维护右端点,取出满足条件的最小值->答案一定不会变劣
如果一次遍历取不到答案->整个方案都不行
代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=100010;
int n;
struct node{
int l,r,num;
int size=0;
bool operator < (const node &x)const{
return r>x.r;
}
}a[N];
int nu[N];
bool cmp(node x,node y){
if(x.l!=y.l) return x.l<y.l;
return x.r<y.r;
}
bool is_ok=true;
priority_queue<node> q;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
a[i].num=i;
a[i].size=a[i].r-a[i].l+1;
}
sort(a+1,a+1+n,cmp);
int p=1;
for(int i=1;i<=n;i++){//枚举排列的每个数
while(p<=n && a[p].l<=i) q.push(a[p++]);
if(!q.size() || q.top().r<i){
is_ok=false;
break;
}
nu[q.top().num]=i;
q.pop();//用完记得弹出
}
if(is_ok){
for(int i=1;i<=n;i++) cout<<nu[i]<<" ";
}else cout<<"-1";
return 0;
}
小O爱论文
https://fjnuacm.top/d/contest/p/P2401B?tid=66f7ba21703d6adf52eb4190
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=100010;
int t;
int n,m;
int x[N],y[N];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>x[i];
for(int i=1;i<=n;i++) cin>>y[i];
ll lin=0;
priority_queue<int> q;
for(int i=1;i<=n;i++){
lin+=x[i];
q.push(y[i]);
//默认每个都阅读
lin-=y[i];
//如果当前精力值不够,就把之前花得最多的弹出去,直到精力值恢复
while(lin<0){
int t=q.top();
q.pop();
lin+=t;
}
//如果已经到达了阅读数 也需要优化
while(q.size()>m){
int t=q.top();
q.pop();
lin+=t;
}
}
int ans=q.size();
if(ans>=m){
cout<<"YES"<<endl;
cout<<lin<<endl;
}
else{
cout<<"NO"<<endl;
cout<<ans<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}
Serval and Kaitenzushi Buffet
https://codeforces.com/contest/2085/problem/D
对应吃的点取最大即可
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int t;
int n,k;
void solve(){
cin>>n>>k;
vector<int> d(n+1);
for(int i=1;i<=n;i++) cin>>d[i];
//只能拿n-k前的
//最多拿几个
int cnt=n/(k+1);
//反悔贪心:在正好能吃完的地方(注意这里 拿值的条件)拿走之前最大的
/*eg
n=6 k=3
6 5 4 3 2 1
√ √
*/
priority_queue<int> q;
ll ans=0;
for(int i=1;i<=n;i++){
q.push(d[i]);
if((n-i+1)%(k+1)==0){
ans+=q.top();
q.pop();
}
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--) solve();
return 0;
}