看不懂G题啥意思,寄!
文章目录
A - Cards for Friends
如果长或宽任意一个为偶数,意味着可以得到当前拥有的Card数的2倍
from math import *
from collections import *
N = int(1e9 + 7)
def read():
return list(map(int, input().strip().split(' ')))
# start
n2, = read()
for _ in range(n2):
w, h, n = read()
piece = 1 # 当前有piece片Card
flag = 0 # 能否成功给所有人送出Card
while True:
if piece >= n:
flag = True
break
if w & 1 == 0:
w //= 2
piece *= 2
elif h & 1 == 0:
h //= 2
piece *= 2
else:
break
if flag:
print('yes')
else:
print('no')
B - Fair Division
根据两种糖果的数量的奇偶性进行判断即可
具体看注释
from math import *
from collections import *
N = int(1e9 + 7)
def read():
return list(map(int, input().strip().split(' ')))
def check(dic):
x, y, s = dic[1] % 2, dic[2] % 2, (dic[1] + dic[2] * 2) % 2
# 总和为奇数,不可能分配成功
if s == 1:
return False
# 下面是总和为偶数时,这时1克重的糖肯定有偶数个
# 2克重的糖有偶数个时,肯定能对半分完
if y == 0:
return True
# 2克重的糖有奇数个时
elif y == 1:
# 没有1克重的糖时,分配完会多出一个2克糖
if dic[1] == 0: return False
# 假设A拿了2颗2g的糖,B拿了3颗2g的糖
# 此时有2颗以上的1g的糖,再给A 2颗1g的糖。剩下的1g的糖平均分配就行
return True
# start
n2, = read()
for _ in range(n2):
n, = read()
a = read()
dic = Counter(a)
print('yes' if check(dic) else 'no')
C - Long Jumps
记忆化搜索
可以从图中看出,如果暴力来做,有重复的地方。
那么我们不妨记录一下从每个点出发所得的分;如果计算过了,那么就不用往下走了。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
int n, a[205000], dp[205000];
int dpp(int i) {
if (i > n) return 0;
if (dp[i] != -1)
return dp[i];
else {
dp[i] = dfs(i + a[i]) + a[i];
return dp[i];
}
}
int main() {
ios::sync_with_stdio(false);
cout.tie(NULL);
// freopen("code.txt", "r", stdin);
int _;
cin >> _;
while (_--) {
int ans = -1;
cin >> n;
_rp(i, 1, n + 1) {
cin >> a[i];
dp[i] = -1;
}
_rp(i, 1, n + 1) { ans = max(ans, dpp(i)); }
cout << ans << endl;
}
return 0;
}
D - Even-Odd Game
不管怎么样,他们两个人都要去拿当前最大的数。
拿Alice举例,如果当前最大的数是偶数,那她肯定要拿,同时加分。 如果是奇数,她拿了虽然不加分,但是对面也拿不到这个大分,经典损人利己法。
最后看一下谁的分多就行
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
ll n, a[205000];
int main() {
ios::sync_with_stdio(false);
cout.tie(NULL);
// freopen("code.txt", "r", stdin);
int _;
cin >> _;
while (_--) {
ll ans = 0;
cin >> n;
_rp(i, 0, n) { cin >> a[i]; }
sort(a, a + n, greater<int>());
_rp(i, 0, n) {
// Alice
if (i % 2 == 0 && a[i] % 2 == 0) ans += a[i];
// Bob
if (i % 2 == 1 && a[i] % 2 == 1) ans -= a[i];
// cout << ans << endl;
}
if (ans > 0)
cout << "Alice" << endl;
else if (ans == 0)
cout << "Tie" << endl;
else
cout << "Bob" << endl;
}
return 0;
}
E - Correct Placement
这题挺有意思的
因为一个人可以躺着或站着,那么我们不妨令
w
=
m
i
n
(
w
,
h
)
,
h
=
m
a
x
(
w
,
h
)
w=min(w,h),h=max(w,h)
w=min(w,h),h=max(w,h),方便处理。(注意不要先让
w
=
m
i
n
(
w
,
h
)
w=min(w,h)
w=min(w,h),此时的w可能会发生变化)
然后使用一个map(mp)记录所有
w
w
w对应的
h
h
h及id
此时,拥有最小的
w
w
w的人的前面肯定无法站人(要满足严格小于才行)。直接记录他们的前面站的人的
i
d
id
id为-1。
用min_h记录当前最小的
h
h
h,min_h_id 记录id
// 如果这个人拥有最小的w,那么他前面一定无法站任何人,记为-1
for (auto [h, id] : mp.begin()->second) {
d[id] = -1;
// 记录当前最小的h的id(id可能有多个,不过无所谓的,题目说任意)
if (h < min_h) {
min_h = h;
min_h_id = id;
}
}
然后开始按
w
w
w从小到大的顺序对这些人遍历
对于
w
=
w
i
w=w_i
w=wi的人,如果他的
h
h
h大于当前min_h,那么说明有某个人的
w
j
<
w
i
且
h
j
<
h
i
w_j<w_i且h_j<h_i
wj<wi且hj<hi,那么我们就让这个人站在他前面。(min_h对应的
w
w
w一定是小于
w
i
w_i
wi)
if (h > min_h) {
d[id] = min_h_id;
}
// 如果连最小的h都比不过,就没必要和其他更大的h进行比较了,此时前面不能站人
else {
d[id] = -1;
}
再次对 w = w i w=w_i w=wi的人遍历他们的 h h h,此时更新min_h。这时候我们就可以保证——在下一次遍历中,min_h所对应的 w j w_j wj一定小于下一次遍历的 w i w_i wi,满足严格 w j w_j wj小于 w i w_i wi的条件
// 再次遍历,看当前w中是否有更小的h为我们所用
// 在下一次遍历中,最小的h所对应的w一定小于下一次遍历的w,满足严格wj小于的条件wi
for (auto [h, id] : it->second) {
if (h < min_h) {
min_h = h;
min_h_id = id;
}
}
最后输出一下答案就行,其实这题用排序也行。。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
ll n;
int d[205000];
int main() {
ios::sync_with_stdio(false);
cout.tie(NULL);
// freopen("code.txt", "r", stdin);
int _;
cin >> _;
while (_--) {
cin >> n;
map<int, list<pair<int, int>>> mp; // 记录所有w对应的h及id
_rp(i, 0, n) {
int w, h;
cin >> w >> h;
mp[min(w, h)].push_back({max(w, h), i + 1});
}
int min_h = 1000000009, min_h_id;
// 如果这个人拥有最小的w,那么他前面一定无法站任何人,记为-1
for (auto [h, id] : mp.begin()->second) {
d[id] = -1;
// 记录当前最小的h的id(id可能有多个,不过无所谓的,题目说任意)
if (h < min_h) {
min_h = h;
min_h_id = id;
}
}
mp.erase(mp.begin()); //处理过了,删掉
// 对w从小到大的顺序进行遍历
for (auto it = mp.begin(); it != mp.end(); it++) {
// cout << "min_h:"<<min_h<<endl;
for (auto [h, id] : it->second) {
// cout << "h:"<<h<<endl;
// 如果此时的h大过最小的h,同时肯定满足 此时的h 大过
// 最小的h的w(因为我们是对w从小到大遍历的) 那么当前的人前面可以站一个人
if (h > min_h) {
d[id] = min_h_id;
}
// 如果连最小的h都比不过,就没必要和其他更大的h进行比较了,此时前面不能站人
else {
d[id] = -1;
}
}
// 再次遍历,看当前w中是否有更小的h为我们所用
// 在下一次遍历中,min_h所对应的w_j一定小于下一次遍历的w_i,满足严格w_j小于w_i的条件
for (auto [h, id] : it->second) {
if (h < min_h) {
min_h = h;
min_h_id = id;
}
}
}
_rp(i, 1, n + 1) { cout << d[i] << ' '; }
cout << endl;
}
return 0;
}
F - Equalize the Array
这里就不拾人牙慧了
和我思路差不多的题解,有图
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<int, int> pii;
#define _rp(i, a, b) for (int i = a; i < b; i++)
int n, m;
pii a[205000];
bool check() {
cin >> n >> m;
_rp(i, 0, m) { cin >> a[i].second >> a[i].first; }
// 奇数一定不行
if (m % 2 == 1) return false;
// 对列排序
sort(a, a + m);
for (int i = 0; i < m - 1; i += 2) {
int j = i + 1, k = j + 1;
// 后面还有两个,且在同一列上
if (k < m && (a[k].first == a[j].first) && (a[k].second != a[j].second)) {
return false;
} else {
// 同列
if (a[i].first == a[j].first) continue;
// 间隔数是否为奇数
int odd = (a[j].first - a[i].first - 1) % 2;
// 同行
if (a[i].second == a[j].second) {
if (odd != 0) return false;
}
// 不同行
else {
if (odd == 0) return false;
}
}
}
return true;
}
int main() {
ios::sync_with_stdio(false);
cout.tie(NULL);
// freopen("code.txt", "r", stdin);
int _;
cin >> _;
while (_--) {
if ((check())) {
cout << "yes\n";
} else {
cout << "no\n";
}
}
return 0;
}