这里写目录标题
A.Not Shading
题意
给你一个m*n的棋盘,每个位置分别放置白棋和黑棋。如果行(列)中有一个黑色棋子可以进行一次操作使得整行(列)中的所有棋子都变成成黑色,问欲使(r,c)位置要变成黑色棋子要进行几次操作?
题解
由于可以进行整行、整列变换,只要棋盘上有一个黑色棋子,那么每个位置都可以变成黑色棋子,所以只有三种情况
1.(r,c)位置上已经是黑色棋子就不用进行操作
2.r行上有一个黑色棋子,或c列上有一个黑色棋子,那么只需要一次操作即可
3.如果r行上和c列上都没有黑色棋子,但是棋盘其他位置有一个黑色棋子,那么进行两次操作即可使得(r,c)位置变成黑色
代码
#include <iostream>
using namespace std;
const int maxn = 55;
char arr[maxn][maxn];
int main(){
//freopen("in.txt","r",stdin);
int t; cin >> t;
for(int T = 1; T <= t; T++){
int n, m, r, c; cin >> n >> m >> r >> c;
bool isblack = false;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> arr[i][j];
if (arr[i][j] == 'B') isblack = true;
}
}
if (arr[r][c] == 'B'){
printf("0\n");
continue;
}
bool ans = false;
for(int i = 1; i <= m; i++){
if (arr[r][i] == 'B') {
ans = true;
break;
}
}
for(int i = 1; i <= n; i++){
if (arr[i][c] == 'B') {
ans = true;
break;
}
}
if (ans){
printf("1\n");
}
else if (isblack){
printf("2\n");
}
else printf("-1\n");
}
}
B. Not Sitting
题意
有一个n*m的座位,T可以进行涂粉色,涂粉色的座位R不坐。T先涂,然后R选座位,要使得无论T怎么选距离都是最近最后T选座位,要尽量原理R,k为 0 0 0 ~ n ∗ m − 1 n*m-1 n∗m−1 时T和R之间的距离
题解
R选择的位置要在中间,这样能确保无论T选择哪里都不会太远而尽量近。那么显然T选择的位置是四个角落的位置其中一个,然后计算每个位置到四个顶点的最大值,进行储存,因为最后选位置的T所以存四点的最大值。
最后对所有最大值进行排序,即为答案,这是由于T的每种k的涂鸦方案所导致的最佳情况,所以为答案。
代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
//const int maxn =
int main(){
//freopen("in.txt","r",stdin);
int t;
cin >> t;
for(int _ = 1; _ <= t; _++){
int n, m; cin >> n >> m;
std::vector<int> v;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
int t1 = abs(i - 1) + abs(j - 1);
int t2 = abs(i - 1) + abs(j - m);
int t3 = abs(i - n) + abs(j - 1);
int t4 = abs(i - n) + abs(j - m);
int maxx = max(max(t1, t2), max(t3, t4));
v.push_back(maxx);
}
}
sort(v.begin(), v.end());
for(auto i: v){
cout << i << " ";
}
cout << '\n';
}
}
C. Not Assigning
题意
题目定义了素数树的概念,
A prime tree is a tree where the weight of every path consisting of one or two edges is prime
定义就帮我们排除了树的度超过2的情况了
及树上任意路径的权重之和都是素数即为素数树,要你求解素数树的权重序列。
题解
参考官方题解所写
1.考虑什么时侯不存在最素数树
即任意顶点的度超过2的时候,素数树是必然不存在的
2.路径怎么样能构成素数?
就需要利用特殊的素数2,因为 3+5=8 奇数+奇数=偶数,偶数必然不会是素数
而2+3=5 即为素数,可以利用这一点交替使用2和3构成全部为素数的路径,从而建立素数树
3.注意素数树是由素数边组成、由素数路径组成即可,并不是要求整条路径之和是素数,参考题目样例
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1e5+50;
std::vector<pair<int, int>> E[maxn];
bool vis[maxn];
int ans[maxn];//记录每条边的长度
int d[maxn];//统计每个点的度数
int vnum = true;//判断度数不符合的情况
void dfs(int root, int weight){
if (vis[root]) return;
vis[root] = true;
for(pair<int, int> i: E[root]){
ans[i.second] = weight + 2;
dfs(i.first, weight^1);
}
}
int main(){
int T; cin >> T;
while(T--){
//初始化
vnum = true;
int n; cin >> n;
for(int i = 0; i <= n; i++){ E[i].clear(); vis[i] = false; d[i] = 0; ans[i] = 0;}
for(int i = 1; i <= n - 1; i++){
int u, v; cin >> u >> v;
E[u].push_back(make_pair(v, i));
E[v].push_back(make_pair(u, i));
d[u]++;
d[v]++;
if (d[u] > 2 || d[v] > 2) vnum = false;
}
if(!vnum) {
printf("-1\n");
continue;
}
int pos = -1;
for(int i = 1; i <= n; i++){
if (d[i] == 1) {
pos = i;
break;
}
}
dfs(pos, 0);
for(int i = 1; i < n; i++) printf("%d ", ans[i]);
cout << '\n';
}
}
D. Not Adding
题目
给你n个不同的数字,一次操作为每两个数字求解GCD如果所得的GCD没有出现在序列中,则加入到序列的末尾,问最多能够操作多少次
题解
n的范围是 1 0 6 10^6 106,那么我们可以考虑枚举这 1 1 1~ 1 0 6 10^6 106这些数字,判断是否有可能出现在序列中。
- 什么情况下会有可能出现x呢?
即,存在 Y 1 Y1 Y1, Y 2 Y2 Y2,……, Y m Y_m Ym ( m > 2 ) (m>2) (m>2) 为 x x x 的倍数
Y i x = t \frac{Y_i}{x}=t xYi=t
因为所有的 Y i Y_i Yi是唯一的,他们又都是x的倍数,所以他们相除所得的公因数只有1
G
C
D
(
Y
1
x
,
Y
2
x
,
…
…
,
Y
m
x
)
=
1
GCD(\frac{Y_1}{x},\frac{Y_2}{x},……,\frac{Y_m}{x}) = 1
GCD(xY1,xY2,……,xYm)=1
上式存在即可说明
x
x
x存在.
判断完
x
x
x出现,并不需要将
x
x
x加入到队列中(就是不需要多加
t
[
x
]
=
1
t[x]=1
t[x]=1这一步操作,这是因为x是因子数)
代码
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 10;
int t[maxn];
//int arr[maxn];
int gcd(int a, int b){
if (b == 0) return a;
else {
return gcd(b, a % b);
}
}
int main(){
//freopen("in.txt","r",stdin);
fill(t, t + maxn, 0);
int n; cin >> n;
for(int i = 0; i < n; i++){
int x; cin >> x;
t[x] = 1;
}
int ans = 0;
for(int i = 1; i < 1e6 + 1; i++){
//if (t[i]) continue;
int temp = 0;
for(int j = i; j < 1e6 + 1; j += i){
if (t[j])
temp = gcd(temp, j / i);
}
if (temp == 1 && !t[i]) {
ans++;
}
}
cout << ans << '\n';
}
E. Not Escaping
题意
简述:要求从建筑物底部 ( 1 , 1 ) (1,1) (1,1)到顶楼 ( n , m ) (n, m) (n,m)逃脱。
该建筑由
n
n
n层组成,每层有
m
m
m个房间。令
(
i
,
j
)
(i,j)
(i,j)表示第
i
i
i层的第
j
j
j个房间。此外,还安装了
k
k
k个梯子。第
i
i
i个梯子允许从
(
a
i
,
b
i
)
(ai,bi)
(ai,bi) 移动到
(
c
i
,
d
i
)
(ci,di)
(ci,di)。如果他使用第
i
个
梯
子
,
可
以
获
得
健
康
点
数
i个梯子,可以获得健康点数
i个梯子,可以获得健康点数hi
。
保
证
所
有
梯
子
的
。保证所有梯子的
。保证所有梯子的ai<ci$。
如果在第
i
i
i 层,可以向左或向右移动。然而,跨楼层旅行是危险的。如果 Ram 从
(
i
,
j
)
(i,j)
(i,j) 移动到
(
i
,
k
)
(i,k)
(i,k),他会失去
∣
j
−
k
∣
⋅
x
i
|j−k|⋅x_i
∣j−k∣⋅xi 健康点。
Ram 在
(
1
,
1
)
(1,1)
(1,1) 处进入大楼,而他的直升机在
(
n
,
m
)
(n,m)
(n,m) 处等待。如果选择最优路径,他损失的最小生命值是多少?
如果无论走哪条路,他都无法逃脱魔掌,则输出“NO ESCAPE”。
题解
每个梯子的开始点即为该行的关键点,每行的关键点不唯一。
每行的移动方向都是向右边移动,那么每行从(i)移动的花费为
f
[
k
]
=
f
[
j
]
−
∣
j
−
k
∣
⋅
x
i
f[k] = f[j]-|j−k|⋅x_i
f[k]=f[j]−∣j−k∣⋅xi
楼层间的旅行是不允许,只能使用梯子。
然后在根据梯子去更新对应的的
f
[
]
f[ ]
f[]