2020.5.6 Codeforces Round #639 (Div. 2)比赛记录

比赛链接

A Puzzle Pieces

就是问用题中特定形状的拼图能不能拼出\(n \times m\)的矩形
分析一下可以发现,如果\(n=1\)或者\(m=1\)肯定是可以的
然后发现最大的块就是\(2 \times 2\)了,也就是说n和m在其它情况都不能大于2

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}

int main(){
	int T = read(),n,m;
	while (T--){
		n = read(); m = read();
		if (n == 1 || m == 1) puts("YES");
		else if (n <= 2 && m <= 2) puts("YES");
		else puts("NO");
	}
	return 0;
}

B Card Constructions

简单题

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int f[maxn],m;
int main(){
	for (m = 1; f[m - 1] <= 1000000000; m++) f[m] = f[m - 1] + 3 * m - 1; 
	m--;
	int T = read();
	while (T--){
		int n = read(),ans = 0;
		for (int i = m; i; i--){
			//cout << f[i] << endl;
			while (f[i] <= n) n -= f[i],ans++;
		}
		printf("%d\n",ans);
	}
	
	return 0;
}

C Hilbert's Hotel

题意是有无穷个房间,标号为全体整数,现在以\(n\)为周期进行调整,在每个周期内模\(n\)\(k\)的房间的客人向前移动\(a_k\)个房间【\(a_k\)可能为负】,问是否会有客人冲突。
显然,如果\(0\)\(n - 1\)通过\(a_k\)变换形成一个与\(0\)\(n-1\)一一对应的映射,那么对于移动后的每个房间,都唯一对应一个开始的位置,没有冲突。
一但形成的映射不是一一对应的,那么一定会有房间冲突。

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 200005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int vis[maxn];
int main(){
	int T = read();
	while (T--){
		int n = read(),flag = true;
		for (int i = 0; i < n; i++) vis[i] = 0;
		for (int i = 0; i < n; i++){
			int x = read();
			if (vis[((i + x) % n + n) % n]) flag = false;
			vis[((i + x) % n + n) % n] = true;
		}
		puts(flag ? "YES" : "NO");
	}
	return 0;
}

D Monopole Magnets

题意是有一个\(n*m\)的矩阵,你可以向其中每个位置放置任意个黑点和白点。符合如下规则:
1、每一列每一行必须有白点
2、所有黑点可以向同一行或同一列的白点所在方向移动任意格。要求带#点必须可以被移动到,剩余带.点必须不能被移动到。
求最少需要多少黑点,或者无解。

分析发现,任意#之间的路径可达,如果两个#之间存在.,那么一定是不合法的。也就是说,#形成的联通块是凸的。
其次如果存在一行全为.且任意一列都有#,那么不合法。因为那一行一定要放置白点,无论放置在哪都会导致该列#处的黑点到达。
然后数一数#联通块个数就是答案了

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 1005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int n,m;
char s[maxn][maxn];
int sumr[maxn][maxn],sumc[maxn][maxn];
int visr[maxn],visc[maxn];
int vis[maxn][maxn],cnt;
int X[] = {0,0,-1,1},Y[] = {-1,1,0,0};
void dfs(int x,int y){
	vis[x][y] = true;
	for (int k = 0; k < 4; k++){
		int nx = x + X[k],ny = y + Y[k];
		if (s[nx][ny] == '#' && !vis[nx][ny]) dfs(nx,ny);
	}
}
int main(){
	n = read(); m = read();
	char c = getchar();
	REP(i,n) REP(j,m){
		while (c != '#' && c != '.') c = getchar();
		s[i][j] = c;
		c = getchar();
	}
	REP(i,n) REP(j,m){
		sumr[i][j] = sumr[i][j - 1];
		sumc[i][j] = sumc[i - 1][j];
		if (s[i][j] == '#'){
			if (!vis[i][j]) cnt++,dfs(i,j);
			sumr[i][j]++; sumc[i][j]++;
			visr[i] = true; visc[j] = true;
		}
	}
	int flag = true;
	//1
	REP(i,n) REP(j,m){
		if (s[i][j] == '.'){
			if (sumr[i][j] && sumr[i][m] > sumr[i][j]) flag = false;
			if (sumc[i][j] && sumc[n][j] > sumc[i][j]) flag = false;
		}
	}
	//2
	int tagr = false,tagc = false;
	REP(i,n) if (!visr[i]) tagr = true;
	REP(j,m) if (!visc[j]) tagc = true;
	if (!tagc) REP(i,n) if (!sumr[i][m]) flag = false;
	if (!tagr) REP(j,m) if (!sumc[n][j]) flag = false;
	if (!flag) puts("-1");
	else printf("%d\n",cnt);
	return 0;
}

E Quantifier Question

【当天cf一直in queue,写到这题就停了,但大概想到做法了】
题意是给出一个公式包含\(n\)变量的若干个\((x_i < x_j)\)的合取的形式,要求给出一个合适的量词,使得公式为真。
量词中\(x_i\)顺序固定,要求使用尽量多的全称量词\(\forall\)

首先我们发现,一个\((x_i <x_j)\)中,假如\(i < j\),那么\(\forall x_j\)一定不合法,因为\(x_i\)在这之前已经固定,存在\(x_j\)使得式子不成立。
所以一开始我们就能确定一些\(x_i\)必须取量词\(\exists x_i\)
对于剩余的,由于不等式的传递性,我们可以进行建图,那么这个图一定是拓扑图,否则公式永假。
然后对于图上每一条路径,形成一个不等关系,路径上每两点之间的不等关系就确定了,同上分析,只有最小的点能取\(\forall\)
那么问题就简单了,只要统计有多少点是进过其路径上编号最小的点。在拓扑图上正着反着dp一下当前最小值就算出来了。

代码略没写

posted @ 2020-05-08 20:55  Mychael  阅读(58)  评论(0编辑  收藏