Codeforces Round #693 (Div. 3)
A. Cards for Friends
大意:
给出纸片长度和宽度w与h,问能否将其分为大于等于n个小纸片
一个纸片如果一条边为偶数,那么可以将其分为两个小纸片
思路:
算出最多能分成多少小纸片即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t;
int main(){
cin>>t;
while(t--){
int w, h, n;
cin >> w >> h >> n;
int sum = 1;
while (w % 2 == 0) w /= 2,sum*=2;
while (h % 2 == 0) h /= 2,sum*=2;
if (sum >= n) cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
B. Fair Division
大意:
有2种糖果,一种重量为1,一种重量为2,现在给出两种糖果的数量,问能否将其分为相等重量的两堆
思路:
如果总重为奇数,肯定为no
否则如果2的数量为偶数,肯定为yes
否则如果1的数量减去2为偶数,肯定为yes
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t;
int main() {
cin >> t;
while (t--) {
int sum1 = 0, sum2 = 0;
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
if (x == 1)
sum1++;
else
sum2++;
}
if ((sum1 + sum2 * 2) % 2 == 1) cout << "NO" << endl;
else{
if(sum2%2==1){
if (sum1>=2&&(sum1 - 2) % 2 == 0) cout << "YES" << endl;
else
cout << "NO" << endl;
}
else{
cout << "YES" << endl;
}
}
}
return 0;
}
C. Long Jumps
大意:
给出一个数组,每次从第i个位置开始,跳转到\(i+a[i]\)的位置,然后权值加上\(a[i]\),然后继续往下跳,问从每个位置开始能获得的最大权值是多少
思路:
直接模拟+记忆化
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t, a[N], n, dp[N];
int dfs(int pos) {
if (pos > n) return 0;
if (dp[pos] != -1) return dp[pos];
return dp[pos] = a[pos] + dfs(pos + a[pos]);
}
int main() {
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[i] = -1;
}
LL res = 0;
for (int i = 1; i <= n; i++) {
LL tmp = a[i];
tmp += dfs(i + a[i]);
res = max(tmp, res);
}
cout << res << endl;
}
return 0;
}
D. Even-Odd Game
大意:
给出n个数,alice先取数,如果取的数为偶数,那么alice的得分加上这个数,否则不加
bob后取,如果取的数为奇数,那么加上这个数,否则不加
问在最优决策下,谁会获胜,或者平局
思路:
先对奇数和偶数分别排序,然后每个人在取数的时候都取最大的奇数和最大的偶数中最大的那个,因为这样就算自己不加分,也可以让对方不加分
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t;
LL a[N], b[N];
int main() {
cin >> t;
while (t--) {
int n;
LL sum1=0, sum2=0;
int cnta = 0, cntb = 0;
cin >> n;
for (int i = 0; i < n; i++) {
LL x;
cin >> x;
if (x & 1)
b[cntb++] = x;
else
a[cnta++] = x;
}
sort(a, a + cnta);
sort(b, b + cntb);
int i = cnta - 1, j = cntb - 1;
for (int k = 0; k < n; k++) {
if (k & 1) {
if (i == -1) {
sum2 += b[j];
j--;
} else if (j == -1)
i--;
else if (a[i] < b[j]) {
sum2 += b[j];
j--;
} else
i--;
} else {
if (i == -1)
j--;
else if (j == -1) {
sum1 += a[i];
i--;
} else if (a[i] > b[j]) {
sum1 += a[i];
i--;
} else
j--;
}
}
if (sum1 == sum2)
cout << "Tie" << endl;
else if (sum1 > sum2)
cout << "Alice" << endl;
else
cout << "Bob" << endl;
}
return 0;
}
E. Correct Placement
大意:
给出n个矩形的长和宽,问对于每个矩形i,能否找到一个其他的矩形j,满足:
$h_j<h_i \(且\)w_j<w_i $
或者
$w_j<h_i \(且\)h_j<w_i $
如果能找到,那么输出任意一个,否则输出-1
思路:
开一个新的数组,存每个矩形翻转后的尺寸,然后对两个数组都排序
排序后维护一个minw数组,代表前i个矩形中最小的w
找的时候直接二分找到比当前矩形的长小的最大的矩形,判断这个minw是否小于w即可
注意排序和二分时用到的cmp函数略有不同,仔细体会一下即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t;
struct node {
int w, h;
int pos;
} a[N], b[N], c[N], minw[N], minh[N];
;
bool cmph2(node a, node b) {
return a.h < b.h;
}
bool cmph(node a, node b) {
if (a.h == b.h)
return a.w < b.w;
else
return a.h < b.h;
}
int main() {
cin >> t;
while (t--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].w >> a[i].h;
a[i].pos = i ;
b[i].w = a[i].h, b[i].h = a[i].w, b[i].pos = a[i].pos;
c[i] = a[i];
}
sort(a+1, a + n+1, cmph);
sort(b+1, b + n+1, cmph);
minw[0].w = minh[0].w = 0x3f3f3f3f;
for (int i =1; i <= n; i++) {
if (a[i].w < minw[i - 1].w) {
minw[i] = a[i];
} else
minw[i] = minw[i - 1];
}
for (int i =1; i <= n; i++) {
if (b[i].w < minh[i - 1].w) {
minh[i] = b[i];
} else
minh[i] = minh[i - 1];
}
for (int i = 1; i <= n; i++) {
int pos = lower_bound(a+1, a + n+1, c[i], cmph2) - a-1;
if (pos != 0) {
if (minw[pos].w < c[i].w) {
//cout << minw[pos].pos << "is"<<minw[pos].w<<"and"<<minw[pos].h<<' ';
cout << minw[pos].pos << ' ';
continue;
}
}
pos = lower_bound(b+1, b + n+1, c[i], cmph2) - b-1;
if (pos != 0) {
if (minh[pos].w < c[i].w) {
cout << minh[pos].pos <<' ';
continue;
}
}
cout << -1 << ' ';
}
cout << endl;
}
return 0;
}
F. New Year's Puzzle
大意:
有一个\(n*2\)的网格,其中有k个位置不能放拼图,现在有\(1*2\)和\(2*1\)的拼图若干,问能否将网格铺满
思路:
从左到右看,第一个不能放拼图的位置(称其为黑块)之前,都是可以铺满的,那么这个黑块就需要和下一个黑块组成一个可以被铺满的小矩形,在纸上画一画可以发现,如果相邻两个黑块的y相同,那么他们的x之差需要是奇数,否则为偶数
所以只需要判断能否将相邻的两个黑块消掉即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t;
struct node {
int x, y;
} a[N];
bool cmp(node a, node b) {
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
int main() {
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
for (int i = 0; i < k; i++) {
cin >> a[i].y >> a[i].x;
}
if (k & 1)
cout << "NO" << endl;
else {
int flag = 1;
sort(a, a + k, cmp);
for (int i = 0; i < k - 1; i++) {
if (a[i].x == a[i + 1].x && i % 2 == 1) {
cout << "NO" << endl;
flag = 0;
break;
}
}
if (flag) {
for (int i = 0; i < k - 1; i += 2) {
if ((a[i + 1].x - a[i].x) % 2 == 0 && a[i].y != a[i + 1].y)
continue;
if ((a[i + 1].x - a[i].x) % 2 == 1 && a[i].y == a[i + 1].y)
continue;
else {
cout << "NO" << endl;
flag = 0;
break;
}
}
if (flag) cout << "YES" << endl;
}
}
}
return 0;
}
G. Moving to the Capital
大意:
给出一个有向图,每个点从自身开始走,可以走任意步,但是只能靠近1号点一次,问每个点距离1号点最近距离是多少
思路:
首先求出每个点到1号点的距离\(dis[i]\),令\(res[i]=dis[i]\)
然后将距离排序,从大到小来考虑
当前点为u,出边相连的点为v,如果\(dis[v]>dis[u]\),那么可以直接走过去,用\(res[v]\)更新\(res[u]\)即可
否则v这个点就是u向1号点靠近的那一点,用\(dis[v]\)更新\(res[u]\)即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t;
int n, m, dis[N], res[N];
struct node {
int id;
int dis;
} a[N];
bool cmp(node a, node b) { return a.dis < b.dis; }
vector<int> mp[N];
int main() {
cin >> t;
while (t--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
dis[i] = -1;
mp[i].clear();
}
for (int i = 0; i < m; i++) {
int x, y;
cin >> x >> y;
mp[x].push_back(y);
}
queue<int> q;
q.push(1);
q.push(0);
while (!q.empty()) {
int now = q.front();
q.pop();
int step = q.front();
q.pop();
if (dis[now] != -1) continue;
dis[now] = step;
for (int i = 0; i < mp[now].size(); i++) {
int ne = mp[now][i];
q.push(ne);
q.push(step + 1);
}
}
for (int i = 0; i < n; i++) {
a[i].id = i + 1;
a[i].dis = dis[i + 1];
res[i + 1] = dis[i + 1];
}
sort(a, a + n, cmp);
for (int i = n - 1; i >= 0; i--) {
int now = a[i].id;
for (int j = 0; j < mp[now].size(); j++) {
int ne = mp[now][j];
if (dis[ne] > dis[now])
res[now] = min(res[now], res[ne]);
else
res[now] = min(res[now], dis[ne]);
}
}
for (int i = 0; i < n; i++) {
cout << res[i+1] << ' ';
}
cout << endl;
}
return 0;
}