【ZROI 537】贪心题 题解

Link

Solution

最大的一边直接放到一起贪心即可

着重讲小的一边

已知对于二分图匹配,其答案即为最大流

令时间集合为 \(T = {1,2,3,\dots,maxt}\)

对于每一门课程,按照如下方式建图:

  • 每个任务为一个点,每个时间为一个点,每个任务向其对应的时间区间连边,源点向每个任务连边,边权为 \(1\),每个时间向汇点连边,边权为 \(1\)

考虑第一门课程:

我们选择一些时间节点分给它,设为 \(T_1\)

假设最大流中任务集合为 \(A\),对应的时间集合为 \(B\),并且 \(|A| =|B|=二分图匹配数量\)

那么根据最大流-最小割定理,相当于在图中割去 \(|A|\) 条边,满足下述性质:

  • 没有从源点到汇点的合法路径

考虑第二门课程:

分给它的时间节点为 \(T_2=\complement _T ^{T_1}\)

这时候假设最大流中任务集合为 \(C\),对应的时间集合为 \(D\),并且 \(|C|=|D|=二分图匹配数量\)

同样拥有上述性质

下面建立新的一张图:

将上述两张图并起来,把左边的汇点和右边的源点去掉,每个左边的时间节点向右边对应的时间节点连边权为 \(1\) 的一条边

下面证明,新图中的每一个割和原来两个图中某两个割的并等价。

  1. 将原图中的两个割放到现在的图上,把左边的图的时间节点到汇点的割变成现在的时间节点到对应时间节点的割,右边类似,由于 \(T_1 \bigcap T_2 = \varnothing\),所以不会有一条中间的边被割两次,那么,对于中间的任意一条边,要么源点无法走到它,要么它无法走到汇点(否则无论它分给哪个课程都不能形成割),所以现在仍旧是一个割
  2. 考虑现在的任意一个割,按照上面的方法把它对应到原来的两张图上,对于每一个中间的边,要么源点不能走向它,要么它不能走向汇点,如果源点不能到他就把它分给源点,否则把它分给汇点,这样原来的两张图仍旧满足割的性质
  3. 综上,命题得证

所以新图的最小割即为答案

Code

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__) ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
} const int maxn = 44000;
int n, m;
pii p[maxn], tp[maxn];
struct lzt {
int fi, se, ii;
bool operator < (const lzt &b) const {
if (fi != b.fi) return fi < b.fi;
if (se != b.se) return se < b.se;
return ii < b.ii;
}
};
lzt a[maxn], b[maxn];
priority_queue<int, vector<int>, greater<int> > pq; namespace task1 {
const int mxst = 1100000;
int f[22][mxst];
void main() {
int mx = (1 << n) - 1, mxt = 0;
rep(i, 1, n) mxt = max(mxt, p[i].se);
rep(i, 1, m) a[i].fi = p[i].fi, a[i].se = p[i].se, a[i].ii = i;
rep(i, m + 1, n) b[i - m].fi = p[i].fi, b[i - m].se = p[i].se, b[i - m].ii = i;
m = n - m; n = n - m;
sort(a + 1, a + n + 1); sort(b + 1, b + m + 1);
rep(i, 0, mxt) rep(j, 0, mx) f[i][j] = 1e9;
f[0][0] = 0;
rep(i, 0, mxt - 1) {
rep(j, 0, mx) {
if (f[i][j] == 1e9) continue;
// 选择第一门
int ind = 0;
rep(k, 1, n) {
if (a[k].fi > i + 1) break;
if (a[k].se < i + 1 || (j & (1 << (k - 1)))) continue;
if (!ind || a[k].se < a[ind].se || (a[k].se == a[ind].se && a[k].ii < a[ind].ii)) ind = k;
}
int nwst = j, ad = 0;
if (ind) nwst += (1 << (ind - 1)), ad = 1;
f[i + 1][nwst] = min(f[i + 1][nwst], f[i][j] + ad);
//选择第二门
int ind2 = 0;
rep(k, 1, m) {
if (b[k].fi > i + 1) break;
if (b[k].se < i + 1 || (j & (1 << (n + k - 1)))) continue;
if (!ind2 || b[k].se < b[ind2].se || (b[k].se == b[ind2].se && b[k].ii < b[ind2].ii)) ind2 = k;
}
int nwst2 = j; ad = 0;
if (ind2) nwst2 += (1 << (n + ind2 - 1)), ad = 1;
f[i + 1][nwst2] = min(f[i + 1][nwst2], f[i][j] + ad);
}
}
int ans = 1e9;
rep(i, 0, mx) ans = min(ans, f[mxt][i]);
printf("%d\n", ans);
}
} namespace task2 {
struct Dinic{
struct Edge{
int fr,to,cap,flow;
};
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int cur[maxn],d[maxn]; void addedge(int u,int v,int cap){
edges.pb((Edge){u,v,cap,0});
edges.pb((Edge){v,u,0,0});
m=edges.size();
G[u].pb(m-2);G[v].pb(m-1);
} bool BFS(){
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
vis[s]=1;
d[s]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(!vis[e.to] && e.cap>e.flow){
vis[e.to]=1;
d[e.to]=d[u]+1;
q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a){
if(x==t || !a) return a;
int f,flow=0;
for(int &i=cur[x];i<G[x].size();i++){
Edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
a-=f;flow+=f;
edges[G[x][i]^1].flow-=f;
if(!a) break;
}
}
return flow;
} int MaxFlow(int s,int t){
this->s=s;this->t=t;
int ret=0;
while(BFS()){
memset(cur,0,sizeof(cur));
ret+=DFS(s,1e9);
}
return ret;
}
} gr;
void main() {
int mxt = 0;
rep(i, 1, n) mxt = max(mxt, p[i].se);
rep(i, 1, m) a[i].fi = p[i].fi, a[i].se = p[i].se, a[i].ii = i;
rep(i, m + 1, n) b[i - m].fi = p[i].fi, b[i - m].se = p[i].se, b[i - m].ii = i;
m = n - m; n = n - m;
int s = n + m + mxt + mxt + 1, t = s + 1;
sort(a + 1, a + n + 1); sort(b + 1, b + m + 1);
rep(i, 1, n) gr.addedge(s, i, 1);
rep(i, 1, m) gr.addedge(i + n, t, 1);
rep(i, 1, mxt) gr.addedge(i + n + m, i + n + m + mxt, 1);
rep(i, 1, mxt) {
rep(j, 1, n) if (a[j].fi <= i && a[j].se >= i) gr.addedge(j, i + n + m, 1e9);
rep(j, 1, m) if (b[j].fi <= i && b[j].se >= i) gr.addedge(i + n + m + mxt, j + n, 1e9);
}
printf("%d\n", gr.MaxFlow(s, t));
}
} void work(){
n = read(), m = read();
rep(i, 1, n) p[i].fi = read(), p[i].se = read();
rep(i, 1, n) tp[i] = p[i];
sort(tp + 1, tp + n + 1);
int nw = 1, ans = 0;
rep(i, 1, 400) {
while (tp[nw].fi <= i && nw <= n) pq.push(tp[nw].se), nw++;
while (!pq.empty() && pq.top() < i) pq.pop();
if (!pq.empty()) ans++, pq.pop();
}
printf("%d\n", ans);
task2::main();
} int main(){
#ifdef LZT
freopen("in","r",stdin);
#endif work(); #ifdef LZT
Debug("My Time: %.3lfms", (double)clock() / CLOCKS_PER_SEC);
#endif
}

【ZROI 537】贪心题 题解的更多相关文章

  1. ACM ICPC 2018 青岛赛区 部分金牌题题解(K,L,I,G)

     目录: K Airdrop I Soldier Game L Sub-cycle Graph G Repair the Artwork ———————————————————— ps:楼主脑残有点严 ...

  2. Codeforces Round #609 (Div. 2)前五题题解

    Codeforces Round #609 (Div. 2)前五题题解 补题补题…… C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了…… 然后因为longlong调了半个小时…… A.Eq ...

  3. NOIP2018初赛普及组原题&题解

    NOIP2018初赛普及组原题&题解 目录 NOIP2018初赛普及组原题&题解 原题&答案 题解 单项选择题 第$1$题 第$2$题 第$3$题 第$4$题 第$5$题 第$ ...

  4. 10.9 guz模拟题题解

    感谢@guz 顾z的题题解 考试共三道题,其中 第一题help共10个测试点,时间限制为 1000ms,空间限制为 256MB. 第二题escape共20个测试点,时间限制为1000ms2000ms, ...

  5. Codeforces Round #599 (Div. 2)的简单题题解

    难题不会啊…… 我感觉写这个的原因就是因为……无聊要给大家翻译题面 A. Maximum Square 简单题意: 有$n$条长为$a_i$,宽为1的木板,现在你可以随便抽几个拼在一起,然后你要从这一 ...

  6. Codeforces Round #612 (Div. 2) 前四题题解

    这场比赛的出题人挺有意思,全部magic成了青色. 还有题目中的图片特别有趣. 晚上没打,开virtual contest打的,就会前三道,我太菜了. 最后看着题解补了第四道. 比赛传送门 A. An ...

  7. Hello2020(前四题题解)

    Hello,2020!新的一年从快乐的掉分开始…… 我在m3.codeforces.com这个镜像网站中一开始还打不开D题,我…… 还有话说今天这场为什么那么多二分. 比赛传送门:https://co ...

  8. Codeforces Round #524 (Div. 2)(前三题题解)

    这场比赛手速场+数学场,像我这样读题都读不大懂的蒟蒻表示呵呵呵. 第四题搞了半天,大概想出来了,但来不及(中途家里网炸了)查错,于是我交了两次丢了100分.幸亏这次没有掉rating. 比赛传送门:h ...

  9. Educational Codeforces Round 53 (Rated for Div. 2) (前五题题解)

    这场比赛没有打,后来补了一下,第五题数位dp好不容易才搞出来(我太菜啊). 比赛传送门:http://codeforces.com/contest/1073 A. Diverse Substring ...

随机推荐

  1. linux 下 监控系统运行状况 命令 dstat

    推荐读文:https://linux.cn/article-3215-1.html

  2. Zookeeper- Error contacting service. It is probably not running解决方案和原理

    搭建启动Zookeeper集群出现Error contacting service. It is probably not running解决方案和原理 1.关闭防火墙  [root@srv01 bi ...

  3. Win7、Win8、Win10始终以管理员身份运行程序。

    在Win7.Win8.Win10系统中,以管理员身份运行程序很麻烦,一般有以下几种方式: 1.在可执行程序或快捷方式上右键,以管理员身份运行: 2.在可执行程序或快捷方式上右键->属性-> ...

  4. 洛谷P1144——最短路计数

    题目:https://www.luogu.org/problemnew/show/P1144 spfa跑最短路的同时记录cnt数组表示到达方案数. 代码如下: #include<iostream ...

  5. The specified named connection is either not found in the configuration, not intended to be used

    今天用EF遇到一个问题, The specified named connection is either not found in the configuration, not intended t ...

  6. C# 对象间的 深拷贝 实现

        以下的这个类实现了 2个含有部分字段名字相同 的对象的 赋值拷贝. public class ShallowCopyHelper     {         public static voi ...

  7. hibernate学习 六 Hibernate缓存

    缓存: 如果在集群环境下使用Hibernate时,(集群有节点A ,节点B) 当请求,发往A节点,A在数据库中修改了一条记录,然后节点B的缓存中如何实时的更新节点A修改的新数据          hi ...

  8. openstack开发环境搭建

    1       目的 让linux下的openstack代码能在windows上面实现同步开发. 2       目标 使用samba实现window与Linux的文件共享. 3       实验环境 ...

  9. 【250】◀▶IEW-Unit15

    Unit 15 Youth Issues 1.model1题目分析 Young people who are still at school often feel just as much stres ...

  10. Spring入门第十三课

    通过FactoryBean来配置Bean package logan.spring.study.factoryBean; public class Car { private String brand ...