【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. javascript类的简单定义

    在面向对象编程中,类(class)是对象(object)的模板,定义了同一组对象(又称"实例")共有的属性和方法. Javascript语言不支持"类",但是可 ...

  2. js中的window.open返回object的错误

    系统中用javascript中的window.open后,页面返回了一个[object].因为系统的原因,必需使用href="javascript:window.open()"这样 ...

  3. 【HDU2050】折线分割平面

    Position Solution 2×n^2-n+1 证明见分割问题 Code // This file is made by YJinpeng,created by XuYike's black ...

  4. 语义分割(semantic segmentation) 常用神经网络介绍对比-FCN SegNet U-net DeconvNet,语义分割,简单来说就是给定一张图片,对图片中的每一个像素点进行分类;目标检测只有两类,目标和非目标,就是在一张图片中找到并用box标注出所有的目标.

    from:https://blog.csdn.net/u012931582/article/details/70314859 2017年04月21日 14:54:10 阅读数:4369 前言 在这里, ...

  5. oracle中导出sql的几个常见词语的意思

    set feedback off不显示反馈信息  “1行已插入”,大量数据装入时,显示这个也是很浪费资源和时间的. set define off 如果你某个字段里面有&字符,插入数据会出错,设 ...

  6. 洛谷 1131 [ZJOI2007]时态同步——树形dp

    题目:https://www.luogu.org/problemnew/show/P1131 因为越高,调节一个影响到的越多,所以底下只要把子树间的差异消除了就行了,与其他部分的差异由更高的边调节. ...

  7. Floyd(稠密图,记录路径)

    #include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #i ...

  8. zk 04之 Zookeeper Api(java)与应用

    如何使用 Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储 ...

  9. WebService基础入门(转)

    一.概念: 1.WebService,顾名思义就是基于Web的服务.它使用Web(HTTP)方式,接收和响应外部系统的某种请求.从而实现远程调用. 2.我们可以调用互联网上查询天气信息Web服务,然后 ...

  10. FZU 2057 家谱(dfs)

    Problem 2057 家谱 Accept: 129    Submit: 356Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem ...