codeforces #305 D Mike and Fish

正解貌似是大暴搜?

首先我们考虑这是一个二分图,建立网络流模型后很容易得出一个算法

S->行 容量为Num[X]/2;

行->列 容量为1 且要求(x,y)这个点存在

列->T 容量为Num[Y]/2

这样子跑网络流之后我们就得到了一组解

但是我们考虑输出方案

对于每一行,如果Num[X]为偶数,那么显然输出方案是正确的

但是如果Num[x]为奇数,多出的那个显然既有可能是红的也可能是蓝的

但关键是我们不能确定他是红的或者蓝的,因为他的状态也会影响对应的列

同样,列的考虑也是同理

所以我们对于残量网络,如果Num[X]或者Num[Y]是奇数,那么就连对应的容量为1的边

对残量网络在进行一次网络流,这样就可以输出方案辣

(话说网络流跑40w的点居然一点也不虚)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define h(i) i
#define l(i) i+200000
using namespace std;

const int maxn=200010;
const int oo=0x7fffffff;
int S,T;
int n,cntx,cnty;
int X[maxn],Y[maxn];
int NX[maxn],NY[maxn];
int idx[maxn],idy[maxn];
bool visx[maxn],visy[maxn];
int h[maxn<<1],cnt=1;
int cur[maxn<<1];
struct edge{
	int to,next,w;
}G[4000010];
int vis[maxn<<1];
queue<int>Q;

void add(int x,int y,int z){
	++cnt;
	G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt;
	++cnt;
	G[cnt].to=x;G[cnt].next=h[y];G[cnt].w=0;h[y]=cnt;
}
void read(int &num){
	num=0;char ch=getchar();
	while(ch<‘!‘)ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}
bool BFS(){
	memset(vis,-1,sizeof(vis));
	Q.push(S);vis[S]=1;
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		for(int i=h[u];i;i=G[i].next){
			int v=G[i].to;
			if(vis[v]==-1&&G[i].w>0){
				vis[v]=vis[u]+1;
				Q.push(v);
			}
		}
	}return vis[T]!=-1;
}
int DFS(int x,int f){
	if(x==T||f==0)return f;
	int w,used=0;
	for(int i=cur[x];i;i=G[i].next){
		if(vis[G[i].to]==vis[x]+1){
			w=f-used;
			w=DFS(G[i].to,min(w,G[i].w));
			G[i].w-=w;G[i^1].w+=w;
			if(G[i].w>0)cur[x]=i;
			used+=w;if(used==f)return used;
		}
	}
	if(!used)vis[x]=-1;
	return used;
}
void dinic(){
	while(BFS()){
		for(int i=S;i<=T;++i)cur[i]=h[i];
		DFS(S,oo);
	}return;
}

int main(){
	read(n);S=0;T=400001;
	for(int i=1;i<=n;++i){
		read(X[i]);read(Y[i]);
		NX[X[i]]++;NY[Y[i]]++;
	}
	for(int i=1;i<=n;++i)add(h(X[i]),l(Y[i]),1);
	for(int i=1;i<=n;++i){
		if(!visx[X[i]]){
			add(S,h(X[i]),NX[X[i]]>>1);
			visx[X[i]]=true;
		}
		if(!visy[Y[i]]){
			add(l(Y[i]),T,NY[Y[i]]>>1);
			visy[Y[i]]=true;
		}
	}
	dinic();
	memset(visx,false,sizeof(visx));
	memset(visy,false,sizeof(visy));
	for(int i=1;i<=n;++i){
		if(!visx[X[i]]){
			visx[X[i]]=true;
			if(NX[X[i]]&1)add(S,h(X[i]),1);
		}
		if(!visy[Y[i]]){
			visy[Y[i]]=true;
			if(NY[Y[i]]&1)add(l(Y[i]),T,1);
		}
	}
	dinic();
	for(int i=1;i<=n;++i){
		if(!G[(i<<1)+1].w)printf("b");
		else printf("r");
	}return 0;
}

  

时间: 2024-09-30 16:14:35

codeforces #305 D Mike and Fish的相关文章

codeforces #305 A Mike and Frog

挺简单的题目,但是有一堆恶心的边界 在刨去恶心的边界之后: 假定我们知道两边的循环节为b1,b2 其中h第一次到达目标的时间为a1,a2 又知道对于答案t t=a1+b1*t1=a2+b2*t2 不妨枚举t1,判断是否存在可行解即可 又因为LCM(b1,b2)就开始循环了 且b1*b2<=b1*mod 所以我们枚举t1的范围在[0,mod]即可 如果在这个范围内无解,则一定无解 #include<cstdio> #include<cstdlib> #include<cs

codeforces #305 B Mike and Feet

跟之前做过的51Nod的移数博弈是一样的QAQ 我们考虑每个数的贡献 定义其左边第一个比他小的数的位置为L 定义其右边第一个比他小的数的位置为R 这个可以用排序+链表 或者 单调队列 搞定 那么对于区间长度1->(R-L-1),该数都可以作为最小值出现 我们在R-L-1上打上标记,最后从后往前来更新答案即可 至此问题得解 #include<cstdio> #include<cstring> #include<iostream> #include<algori

codeforces #305 E Mike and friends

原问题可以转化为:给定第k个字符串,求它在L-R的字符串里作为子串出现了多少次 定义子串为字符串的某个前缀的某个后缀(废话) 等价于我们把一个字符串插入到trie里,其过程中每个经过的节点和其向上的fail链上的点都是该字符串的子串 又因为对于一条fail链,u向上能访问到v当前仅当u在v的子树内 那么原问题又变成了: 将L-R个字符串按照上述方法插入到trie中并将经过的节点的val值增加 求第k个字符串对应的单词节点在fail树上的子树的权值和 又因为查询的信息满足区间可减性,所以我们可以建

Codeforces 247D Mike and Fish

Mike and Fish 我们可以把这个模型转换一下就变成有两类点,一类是X轴, 一类是Y轴, 每个点相当于对应的点之间建一条边, 如果这条边变红两点同时+1, 变蓝两点同时-1. 我们能发现这个图其实是个二分图, 我们可以随便取一个点开始走路, 红蓝间隔开来,那么中间的点就权值不变, 对于最末尾的点虽然权值有改变,但是只会改变一次, 就这样一直走路直到所有的边都遍历完. #include<bits/stdc++.h> #define LL long long #define fi firs

CF 547 D. Mike and Fish

D. Mike and Fish http://codeforces.com/contest/547/problem/D 题意: 给定平面上n个点,将这些点染成红或者蓝色,要求每行.每列红色点与蓝色点数量的差的绝对值<=1.输出方案(保证有解). 分析: 参考popoqqq的博客 将每行每列分别看做一个点,给定的每个点(x,y)拆成x->y的边,那么连边后的图是一个二分图. 这样我们可以将边染色,使得与每个点相连的两种颜色差<=1. 于是对于所有的欧拉回路,我们可以直接交替染色. 但是会

Codeforces 798D:Mike and distribution

Codeforces 798D:Mike and distributio 题目链接:http://codeforces.com/problemset/problem/798/D 题目大意:给出两个大小为$n$的数列$A,B$,现要求从这两个数列相同位置取出$K(K \leqslant n/2+1)$个数,使得$2 \times subA>sumA$且$2 \times subB>sumB$. 想法题 我们需要从数列$A$和数列$B$中取出$K$个数,使得这$K$个数的和比剩下$n-K$个数的和

codeforces 547D Mike and Fish 欧拉路径

题目链接:点击打开链接 题意: 给定二维平面上的n个点的坐标 问: 把每个点用红色或蓝色染色, 使得 水平共线(或者垂直共线)的 点 中红色与蓝色数量差不超过1. 思路: 我们建一个二部图,X集是x轴,Y集是y轴 那么点(1,5)就是 x集的 1向 y集的 5连一条边. 此时点就是用边来表示的,那我们的任务就是给边染色. 使得: 对于二部图中任意一个点, 点所连接的红边和蓝边数量差不超过1. 那么我们可以认为这个点的入边就是红色,出边就是蓝色.显然这就是一个欧拉路径. 所以爆搜欧拉路径即可. #

codeforces #547D Mike and Fish 欧拉回路

题目大意:给定平面上的n个点,要求将每个点染成红色/蓝色,使得每行/每列的红色点数和蓝色点数之差≤1 将每一个横坐标/纵坐标看做一个点,每个点看做一条连接两个坐标的边 现在我们要将每条边染色使得每个点连接的所有边中两种颜色之差≤1 首先找到度数为奇数的点 这样的点一定有偶数个 将度数为奇数的点两两配对连边,这样所有点的度数就都是偶数了 然后对于每个连通块,任选一个初始度数为奇数的点(不存在则任选一个度数为偶数的点),求一条欧拉回路(如果起始点初始度数为奇数则要求先遍历新连接的边),然后将路径上的

codeforces 361 B - Mike and Shortcuts

Time Limit:3000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Description Recently, Mike was very busy with studying for exams and contests. Now he is going to chill a bit by doing some sight seeing in the city. City consists of n int