【Timus 1099】Work Scheduling

题目传送门:http://acm.timus.ru/problem.aspx?space=1&num=1099
离线版题目:http://paste.ubuntu.com/19164744/

一般图匹配的板题
然而抄范大神的代码抄错了,调了一个下午QAQ
详细情况见之后的博文吧,会单独写一篇算法笔记的

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 1000000;

int n,match[MAXN],fa[MAXN],que[MAXN],fro,bak;
int next[MAXN],mark[MAXN],vis[MAXN];
int T,nxt[MAXN],head[MAXN],to[MAXN];

inline int find(int w){
	int f = fa[w], tmp;
	while (f != fa[f]) f = fa[f];
	while (w != f) tmp=fa[w], fa[w]=f, w=tmp;
	return f;
}

inline void merge(int a, int b){
	int f1 = find(a), f2 = find(b);
	if (f1 != f2) fa[f1] = f2;
}

inline int LCA(int x, int y){
	static int t = 0; t++;
	while (true){
		if (x) {
			x = find(x);
			if (vis[x] == t) return x;
			else {
				vis[x] = t;
				x = next[match[x]];
			}
		} swap(x, y);
	}
}

inline void gather(int a, int p){
	while (a != p){
		int b = match[a], c = next[b];
		if (find(c) != p) next = b;
		if (mark[b] == 2) mark[que[++fro]=b] = 1;
		if (mark == 2) mark[que[++fro]=c] = 1;
		merge(a, b); merge(b, c);
		a = c;
	}
}

inline void Augment(int s){
	for (int i=1;i<=n;i++) next[i]=mark[i]=vis[i]=0, fa[i]=i;
	mark[s] = 1; que[fro=bak=1] = s; 
	while (bak <= fro) {
		int w = que[bak++];
		for (int i=head[w];i;i=nxt[i]){
			if (match[w] == to[i]) continue;
			else if (find(to[i]) == find(w)) continue;
			else if (mark[to[i]] == 2) continue;
			else if (mark[to[i]] == 1) {
				int lca = LCA(w, to[i]);
				if (find(w) != lca) next[w] = to[i];
				if (find(to[i]) != lca) next[to[i]] = w;
				gather(w, lca);
				gather(to[i], lca);
			} else if (!match[to[i]]) {
				next[to[i]] = w;
				for (int u=to[i]; u; ) {
					int v = next[u];
					int fv = match[v];
					match[v] = u; match[u] = v;
					u = fv;
				}
				return;
			} else {
				next[to[i]] = w;
				mark[que[++fro] = match[to[i]]] = 1;
				mark[to[i]] = 2; 
			}
		}
	}
}

inline void AddEdge(int a, int b){
	to[++T] = b; nxt[T] = head[a]; head[a] = T;
	to[++T] = a; nxt[T] = head[b]; head[b] = T;
}

int main(){
	scanf("%d",&n); int a,b;
	while (~scanf("%d%d",&a,&b)) AddEdge(a, b);
	for (int i=1;i<=n;i++) if (!match[i]) Augment(i);
	
	int vout = 0;
	for (int i=1;i<=n;i++) if (match[i]) vout++;
	printf("%d\n",vout);
	for (int i=1;i<=n;i++) if (match[i] > i) printf("%d %d\n",i,match[i]);
	return 0;
}

另外,此题有坑QAQ
边数巨多,TM还不告诉你是RE,给你说的是TLEQAQ

【CDOJ 79】Playground

题目传送门:http://www.acm.uestc.edu.cn/#/problem/show/79
数据生成器:http://paste.ubuntu.com/18848244/

这个题,并查集搞一搞就过了。
然而后来得知一种二分图匹配的思路,感觉很科学,叉不掉。于是写了写代码。
最后发现,二分图匹配的话,只能保证在满足限制的情况下,得出最少解,并不能保证全部染完,比如十字架

#include<iostream>
#include<cstdio>
using namespace std;

const int MAXN = 500;

int fa[MAXN],n,tag[MAXN],vout,que[MAXN],mat[MAXN][MAXN];

inline int find(int w){
	int f=fa[w], tmp;
	while (f != fa[f]) f = fa[f];
	while (w != f) tmp = fa[w], fa[w] = f, w = tmp;
	return f;
}

inline void connect(int a, int b){
	int f1 = find(a), f2 = find(b);
	if (f2 != f1) fa[f2] = f1;
}	

inline void solve(int sta){
	int tot = 0, ret = 0;
	for (int i=1;i<=n*2;i++)
		if (fa[i] == sta)
			que[++tot] = i;
	for (int i=1;i<=tot;i++) if (tag[que[i]]){
		int w = que[i]; ret++;
		if (w <= n){ 
			for (int j=1;j<=n;j++)
				if (mat[w][j]) tag[n+j] = 0;
		} else {
			for (int j=1;j<=n;j++)
				if (mat[j][w-n]) tag[j] = 0;
		}
	}
	vout += min(ret, tot-ret);
}

int main(){
	int T; cin>>T;
	while (T--){
		scanf("%d",&n); vout = 0;
		for (int i=1;i<=2*n;i++) fa[i] = i;
		for (int j=1,tmp;j<=n;j++){
			for (int i=1;i<=n;i++){
				scanf("%d",&tmp);
				mat[i][j] = tmp;
				if (tmp == 1) 
					connect(i,j+n), 
					tag[i] = tag[j+n] = 1;
			}
		}	
		for (int i=1;i<=n*2;i++) fa[i] = find(i);
		for (int i=1;i<=n*2;i++) if (fa[i]==i & tag[i])
			solve(fa[i]);
		printf("%d\n",vout);
	}	
	return 0;
} 

【日常小测】再次挑战NPC

题目传送门:http://oi.cyo.ng/wp-content/uploads/2016/06/water_meeting.pdf

一看这题,TM这不今年wc的T1吗?哎呀,还是不会带花树QAQ,哎呀冬令营的时候网络流搞了40分,那就来写网络流吧!
于是开始骚写网络流。 然后写完了发现过不了样例QAQ 然后想了几分钟突然发现:
如果只考虑奇偶的话,这个一个联通块里不最多只有一个半空的筐QAQ
于是最后写了一个并查集。 后来问一问,发现带花树也是可以的,但是只有80分(╯-_-)╯╧╧

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return buf*f;
}	

const int MAXN = 400000;
const int INF = 100000000;

int n,m,A[MAXN],B[MAXN],bot[MAXN];
int vout,fa[MAXN],sum[MAXN],str[MAXN];
int Q[MAXN],cnt;

inline int find(int w){
	int f=fa[w],tmp;
	while (f != fa[f]) f=fa[f];
	while (w != f) tmp=fa[w],fa[w]=f,w=tmp;
	return f;
}

inline void connect(int b, int a){
	int f1=find(a),f2=find(b);
	if (f1 != f2) fa[f1] = f2;
}

int main(){
	freopen("cpn.in","r",stdin);
	freopen("cpn.out","w",stdout);
	n = read(); m = read();
	for (int i=1;i<=m;i++) fa[i] = i;
	for (int i=1;i<=n;i++){ 
		A[i] = read(); B[i] = read();
		bot[A[i]]++; connect(A[i],B[i]);
	}	
	for (int i=1;i<=m;i++) find(i);
	for (int i=1;i<=m;i++) if (bot[i]%2)
		{sum[fa[i]]++; str[fa[i]] = i;}
	for (int i=1;i<=m;i++) if (sum[i]%2)
		{vout++; Q[++cnt]=str[i];}
	 
	printf("%d\n",vout);
	for (int i=1;i<=cnt;i++)
		printf("%d\n",Q[i]);
	
	return 0;
} 

【BZOJ 3325】[Scoi2013] 密码

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3325
离线版题目:http://paste.ubuntu.com/18029355/
数据生成器:http://paste.ubuntu.com/18029394/

最近都在做字符串,所以接触了一点逆向字符串的题目,于是这题就会做啦!
这类给你字符串结构的过程数组,叫你统计方案数/构造符合要求的字符串,说到底就是给了你一堆字符等与不等的关系
而你就需要根据具体数据结构的特点来处理这些关系
比如说这道题,我上周六想了半个小时,一点思路都没有,觉得提供的关系可能是O(n^2)的。
但今天再来想的时候发现,相等关系可以用和manacher时间复杂度一样的整法证到时O(n)的
而不等关系很明显是O(n)的,于是保存好关系,并查集缩一缩点就搞好啦!
基本上1A! 撒花! *★,°*:.☆\( ̄▽ ̄)/$:*.°★*

#include<iostream>
#include<cstdio>
#include<set>
#define SITR set<int>::iterator
using namespace std;

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return buf*f;
}

const int MAXN = 100000+9;
const int SIGMA_SIZE = 26;

int ld[MAXN],lo[MAXN],fa[MAXN];
int n,mx=1,vout[MAXN],col[MAXN];
set<int> Q[MAXN];

inline int find(int w){
	int f=fa[w],tmp;
	while (fa[f] != f) f=fa[f];
	while (w != f) tmp=fa[w],fa[w]=f,w=tmp;
	return f;
}

inline void connect(int a, int b){
	int f1=find(a), f2=find(b);
	if (f1 != f2) fa[f1] = f2;
}

inline void discon(int a, int b){
	Q[fa[a]].insert(fa[b]);
	Q[fa[b]].insert(fa[a]);
}

int main(){
	n = read(); 
	for (int i=1;i<=n;i++) fa[i] = i; 
	for (int i=1;i<=n;i++) ld[i] = (read()-1)/2;
	for (int i=1;i<n;i++)  lo[i] = read()/2;
	
	for (int i=1;i<=n;i++){
		for (int j=max(mx-i+1,1);j<=ld[i];j++)
			connect(i+j,i-j);	
		mx = max(mx, i+ld[i]);
		
		for (int j=max(mx-i+1,1);j<=lo[i];j++)
			connect(i+j,i-j+1);		
		mx = max(mx, i+lo[i]);
	}
	for (int i=1;i<=n;i++)  fa[i]=find(i);
	for (int i=1;i<=n;i++){ if (i-ld[i] > 1 && i+ld[i] < n) discon(i+ld[i]+1,i-ld[i]-1); if (i-lo[i] > 0 && i+lo[i] < n) 
			discon(i+lo[i]+1,i-lo[i]);
	}
	
	for (int i=1;i<=n;i++){
		if (vout[fa[i]]) continue;
		else {
			for (SITR j=Q[fa[i]].begin();j!=Q[fa[i]].end();j++)
				col[vout[*j]] = i;
			for (int j=1;j<=SIGMA_SIZE;j++)
				if (col[j] < i) {vout[fa[i]] = j; break;}
		}
	}
	
	for (int i=1;i<=n;i++) putchar(vout[fa[i]]+'a'-1);
	
	return 0;
}