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一下当前最小值就算出来了。
代码略没写