首页 > 其他分享 >Greedy

Greedy

时间:2023-11-08 10:13:30浏览次数:24  
标签:__ ... int long Greedy file define

贪心整合包

Tricks
  1. 有些时候贪心是无法证明交换性的,一定要注意交换性是不是对的!即“我不要的你是否一定能拿到”
  2. 反悔贪心的用法:一个物品必然被某个人选,那么我们可以把它加进优先队列里,以后来人的时候再慢慢替换。
  3. 和区间有关的匹配可以用 Hall 定理很好地解释!
  4. Hall 定理求最大匹配是 \(|X|-\max(|S|-R(|S|))\),想求 \(\max(|S|-R(|S|))\),可以考虑求 \(R(|S|)\) 的补集的最大值,这样 \(\max\) 里面是加号,有利于处理。

ARC076D Exhausted?

简要题意:有 \(n\) 个人 \(m\) 张椅子,第 \(i\) 个人只愿意坐在第 \(L_i\) 个椅子之前或第 \(R_i\) 个椅子之后,求至多有几个人坐下来。\(n,m\le 2\times 10^5,0\le L_i<R_i\le m+1\)。

Fake Solution

直接贪心,把所有人按 \(L_i\) 从小到大排序,\(L_i\) 相同的按 \(R_i\) 从大到小排序,然后贪心选,如果能放左边就放左边,否则放到右边的一个队列里面,左边放完之后再对右边排序处理。

Hack
3 4
1 3
2 5
2 5


bigger:

12 10
6 7
0 9
5 10
0 9
2 5
3 9
2 8
3 10
6 7
5 9
4 9
3 9
Real Solution

为什么这种贪心是错的?因为我们想“证明”的交换性是错的。一开始想的“交换性”是基于“如果我的左端点靠前,那‘别人占我的位置,我拿其他位置’不如‘我占我的位置,别人拿那个其他位置’”,但是这是错的,因为“其他位置”别人不一定拿得到。没有正视这个漏洞而随手写了一发,居然过了,但是被题解区 hack 了。

做法一

还是要处理这种情况,可以考虑的一点是反悔贪心。事实上,我们之前的结论中有一点是正确的:我的这个位置,要么我占了,要么回头别人占了,一定不会空着。所以用反悔贪心来考虑,如果我有位置,我就暂时占着;如果我没位置了,那我就到前面去看看有没有适合抢的,如果有就抢一个,把多出来的那个塞到后面去。什么情况下“适合抢”呢?如果我的 \(R_i\) 要大于对方的 \(R_j\),那我确实更紧迫,留下我不如留下他,这个交换性是可以证的,所以我就可以把他换出来。剩下的右半部分照样处理。

做法二

这种问题可以被视为是最大匹配问题,可以尝试用 Hall 定理解决。Hall 定理有一个很有用的推论:最大匹配的大小为 \(|X|-\max(|S|-R(|S|))\)。对应到这道题上,我们要求最大匹配,就是要找出若干个集合,使(集合数量 - 它们的并的大小)最大,答案为 \(n\) 减去这个最大值。对于最大值中出现减号的问题,可以考虑将其取补集。所以变成最大化(集合数量 + 区间的交的大小),则发现区间的交可以偏小,所以枚举这个交集看有几个区间包含它即可。可以线段树优化到 \(O(n\log n)\)。

Fake Code
#include "bits/stdc++.h"
#ifdef DEBUG
#include "PrettyDebug.hpp"
#else
#define debug(...) [](auto...){}(__VA_ARGS__)
#define debuga(...) [](auto...){}(__VA_ARGS__)
#endif
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rev(i,a,b) for(int i=(a);i>=(b);i--)
#define Fin(file) freopen(file,"r",stdin)
#define Fout(file) freopen(file,"w",stdout)
#define assume(expr) ((!!(expr))||(exit((fprintf(stderr,"Assumption Failed: %s on Line %d\n",#expr,__LINE__),-1)),false))
#define fi first
#define se second
using namespace std; typedef long long ll; using pii = pair<int,int>;
constexpr int N=2e5+5;
int n,m; vector<int> lis[N]; priority_queue<int> q;
signed main(){
    // Fin("hh.in");
    atexit([](){cerr<<"Time = "<<clock()<<" ms"<<endl;});
    cin>>n>>m; For(i,1,n) { int x,y; cin>>x>>y; lis[x].push_back(y); }
    int ans=0,use=0; vector<int> vec; for(int u:lis[0]) vec.push_back(m-u+1);
    For(x,1,m){
        for(int u:lis[x]) q.push(u);
        while(q.size()&&use<x) use++,q.pop();
        while(q.size()) vec.push_back(m-q.top()+1),q.pop();
    }
    sort(vec.begin(),vec.end()); //debug(vec,use);
    int lim=m-use; use=0; for(int x:vec) if(use<min(x,lim)) use++; else ans++;
    cout<<ans<<'\n';
    return 0;
}

// START TYPING IF YOU DON'T KNOW WHAT TO DO
// STOP TYPING IF YOU DON'T KNOW WHAT YOU'RE DOING
// CONTINUE, NON-STOPPING, FOR CHARLIEVINNIE

// Started Coding On: November 08 Wed, 07 : 51 : 25
Real Code(做法一)
#include "bits/stdc++.h"
#ifdef DEBUG
#include "PrettyDebug.hpp"
#else
#define debug(...) [](auto...){}(__VA_ARGS__)
#define debuga(...) [](auto...){}(__VA_ARGS__)
#endif
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rev(i,a,b) for(int i=(a);i>=(b);i--)
#define Fin(file) freopen(file,"r",stdin)
#define Fout(file) freopen(file,"w",stdout)
#define assume(expr) ((!!(expr))||(exit((fprintf(stderr,"Assumption Failed: %s on Line %d\n",#expr,__LINE__),-1)),false))
#define fi first
#define se second
using namespace std; typedef long long ll;
constexpr int N=2e5+5; using pii = pair<int,int>;
int n,m; pii a[N]; priority_queue<int,vector<int>,greater<>> q;
signed main(){
    atexit([](){cerr<<"Time = "<<clock()<<" ms"<<endl;});
    cin>>n>>m; For(i,1,n) cin>>a[i].fi>>a[i].se;
    sort(a+1,a+1+n); int use=0; vector<int> vec;
    For(i,1,n){
        q.push(a[i].se);
        if(use<a[i].fi) use++;
        else vec.push_back(m-q.top()+1),q.pop();
    }
    int lim=m-use; use=0; int ans=0; sort(vec.begin(),vec.end()); debug(vec);
    for(int x:vec) if(use<min(x,lim)) use++; else ans++;
    cout<<ans<<'\n';
    return 0;
}

// START TYPING IF YOU DON'T KNOW WHAT TO DO
// STOP TYPING IF YOU DON'T KNOW WHAT YOU'RE DOING
// CONTINUE, NON-STOPPING, FOR CHARLIEVINNIE

// Started Coding On: November 08 Wed, 09 : 01 : 49
暴力&gen(对拍用)
#include "bits/stdc++.h"
#ifdef DEBUG
#include "PrettyDebug.hpp"
#else
#define debug(...) [](auto...){}(__VA_ARGS__)
#define debuga(...) [](auto...){}(__VA_ARGS__)
#endif
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rev(i,a,b) for(int i=(a);i>=(b);i--)
#define Fin(file) freopen(file,"r",stdin)
#define Fout(file) freopen(file,"w",stdout)
#define assume(expr) ((!!(expr))||(exit((fprintf(stderr,"Assumption Failed: %s on Line %d\n",#expr,__LINE__),-1)),false))
using namespace std; typedef long long ll;
constexpr int N=15;
int n,m,L[N],R[N],ans,vis[N];
void dfs(int u,int res){
    if(res>ans) return;
    if(u==n+1) return ans=min(ans,res),void();
    For(i,1,L[u]) if(!vis[i]){
        vis[i]=1; dfs(u+1,res); vis[i]=0;
    }
    For(i,R[u],m) if(!vis[i]){
        vis[i]=1; dfs(u+1,res); vis[i]=0;
    }
    dfs(u+1,res+1);
}
signed main(){
    atexit([](){cerr<<"Time = "<<clock()<<" ms"<<endl;});
    cin>>n>>m; For(i,1,n) cin>>L[i]>>R[i];
    ans=1e9; dfs(1,0); cout<<ans<<'\n';
    return 0;
}

// START TYPING IF YOU DON'T KNOW WHAT TO DO
// STOP TYPING IF YOU DON'T KNOW WHAT YOU'RE DOING
// CONTINUE, NON-STOPPING, FOR CHARLIEVINNIE

// Started Coding On: November 08 Wed, 08 : 22 : 39
#include "bits/stdc++.h"
#ifdef DEBUG
#include "PrettyDebug.hpp"
#else
#define debug(...) [](auto...){}(__VA_ARGS__)
#define debuga(...) [](auto...){}(__VA_ARGS__)
#endif
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rev(i,a,b) for(int i=(a);i>=(b);i--)
#define Fin(file) freopen(file,"r",stdin)
#define Fout(file) freopen(file,"w",stdout)
#define assume(expr) ((!!(expr))||(exit((fprintf(stderr,"Assumption Failed: %s on Line %d\n",#expr,__LINE__),-1)),false))
using namespace std; typedef long long ll;
mt19937 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
long long rnd(ll l,ll r) { return uniform_int_distribution<ll>(l,r)(rng); }
void rnd(long long& l,long long& r,long long n) { l=rnd(1,n); r=rnd(1,n); if(l>r) swap(l,r); }
void rnd(int& l,int& r,int n) { l=rnd(1,n); r=rnd(1,n); if(l>r) swap(l,r); }
signed main(){
    atexit([](){cerr<<"Time = "<<clock()<<" ms"<<endl;});
    int n=12,m=10; cout<<n<<' '<<m<<'\n';
    For(i,1,n) { int l=0,r=0; while(l==r) l=rnd(0,m+1),r=rnd(0,m+1);; if(l>r) swap(l,r);; cout<<l<<' '<<r<<'\n'; }
    return 0;
}

// START TYPING IF YOU DON'T KNOW WHAT TO DO
// STOP TYPING IF YOU DON'T KNOW WHAT YOU'RE DOING
// CONTINUE, NON-STOPPING, FOR CHARLIEVINNIE

// Started Coding On: November 08 Wed, 08 : 24 : 38

标签:__,...,int,long,Greedy,file,define
From: https://www.cnblogs.com/Charlie-Vinnie/p/17816690.html

相关文章

  • Greedy algorithm basic principle
    贪心算法是以动态规划方法为基础的,在每个贪心算法之下,几乎总有一个更繁琐的动态规划算法。贪心算法和动态规划不同之处在于:是否需要考虑子问题的解贪心算法并不考虑子问题,直接在当前步骤中做出选择动态规划无论是自底向上,贪心算法设计步骤将最优化问题转化为这样的形式:对其......
  • [USACO19DEC] Greedy Pie Eaters P 区间dp
    题目背景FarmerJohnhasMMcows,convenientlylabeled1…M1…M,whoenjoytheoccasionalchangeofpacefromeatinggrass.Asatreatforthecows,FarmerJohnhasbakedNNpies(1≤N≤3001≤N≤300),labeled1…N1…N.Cowiienjoyspieswithlabelsinther......
  • greedy2309
    本来前面还有一点内容的,但是今天手残把文件从U盘里误删了,费了好大功夫恢复出来的时候发现前面一点内容已经被一段不知名且缺胳膊少腿的代码覆盖了,所以就只能这样了。这启发我没事多备份备份以防悲剧发生。\(\color{red}{\text{CF1661F*2600}}\)可以推广到许多函数上。所以可以......
  • 【倍增】ABC212F Greedy Takahashi 题解
    ABC212F暴力就是直接跳,显然不可过。考虑对暴力进行优化,发现整个图是不会改变的,容易想到使用倍增。显然是对边进行倍增的,令\(f_{i,j}\)表示从第\(i\)条边开始,跳了\(2^j\)条边后,到的是哪一条边,如果不存在,则设为\(-1\)。然后就是很显然的倍增了,最后讨论一下即可。时间复......
  • Greedy
    P4090[USACO17DEC]GreedyGiftTakersP我们可以发现构成循环的一定是前面的任意一个前缀。考虑二分答案。然后,我们对于这个分界点\(mid\),我们需要知道他是否能被移动到开头。贪心的考虑,我们优先让\(c\)小的移动到后面,这样大的更容易移动到后面。可以使用计数排序,时间复......
  • 2023.9.13 greedy and DS
    CF1439C考虑修改操作,由于序列是单调的,所以只需要线段树二分出修改的区间即可。考虑查询,一定是若干个连续段,设一开始是\(y\),这个连续段结束后,\(y\)至少减去一半,所以连续段个数是\(\log\)级别。在线段树上遍历即可。......
  • CF1132G Greedy Subsequences
    简单题。\(i\)向\(i\)后第一个\(j\),\(a_j\)比\(a_i\)大的点连边,不难发现最后形成了一棵森林,并且一个点的父亲\(\text{fa}_i>i\)。题目变成了取\([l,r]\)中的点为起点,向祖先方向走去并且终点编号\(\ler\)的最长链长度。考虑离线,维护从每个点开始的最长链长度\(f_i......
  • AtCoder Beginner Contest 212 F Greedy Takahashi
    洛谷传送门AtCoder传送门考虑每条边,因为是静态的,所以可以预处理出\(f_{i,j},g_{i,j}\)表示从第\(i\)条边,往后跳\(2^j\)条边,跳到边的编号和目前的时间(如果不存在就当作跳到第\(0\)条边)。直接倍增处理即可。询问就是找到从\(u\)开始的出边,能跳尽量跳。注意一些细节......
  • 【多臂赌机】基于时变egreedy策略结合强化学习求解多臂赌机问题附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • Codeforces Round #225 (Div. 2) C. Milking cows Greedy
    Iahubhelpshisgrandfatheratthefarm.Todayhemustmilkthecows.Therearencowssittinginarow,numberedfrom1tonfromlefttoright.Eachcowiseitherfacingtotheleftorfacingtotheright.WhenIahubmilksacow,allthecowsthatseet......