题目链接:https://codeforces.com/contest/1472
A. Cards for Friends
题目大意
一张纸长为w,宽为h,如果w或h是偶数,那么可以将其分为两半张纸,两张纸重复同样动作,问一张纸能否分成不低于n份
思路
将w,h分别分解,一直除以2,直到不能除为止,分成t1,t2份,那么一共有t1*t2份。
这里可以暴力除,也可以直接用位运算,也就是lowbit(取二进制中从最后一个1的位置开始剩下的数)。
AC代码
暴力
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int t; cin >> t;
while(t --){
int w, h, n;
cin >> w >> h >> n;
int t1 = 1, t2 = 1;
while(w % 2 == 0) {
t1 *= 2;
w /= 2;
}
while(h % 2 == 0){
t2 *= 2;
h /= 2;
}
if(t1 * t2 >= n) puts("YES");
else puts("NO");
}
return 0;
}
lowbit
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & (-x)
int main(){
int t; cin >> t;
while(t --){
int w, h, n;
cin >> w >> h >> n;
int t1 = lowbit(w), t2 = lowbit(h);
if(t1 * t2 >= n) puts("YES");
else puts("NO");
}
return 0;
}
B. Fair Division
题目大意
n块糖,重量要么是1,要么是2,问能否分成相同重量的两份
思路
求出1的个数t1,2的个数t2,总重量s。
如果s是奇数,肯定不行;
如果分成两半,每人分到的重量是奇数,但是没有重量为1的糖果,那也不行。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int t; cin >> t;
while(t --){
int s = 0, n, t1 = 0, t2 = 0, x;
cin >> n;
while(n --){
cin >> x;
t1 += (x == 1);
t2 += (x == 2);
s += x;
}
if(s % 2){
puts("NO");
continue;
}
s /= 2;
if(s % 2 && !t1) puts("No");
else puts("YES");
}
return 0;
}
C. Long Jumps
题目大意
n个数存数组a,从第i个位置开始,中间位置tt初始化为i,然后每次可以跳a[tt]的距离。
如果tt<=n,那么可以继续跳,否则结束游戏,tmp为中途跳的权值和,现在问这个tmp的最大值是多少。
思路
每个位置都可以一直跳,跳出n,如果从左往右遍历的话,举个例子,如果1可以跳到6,3可以跳到6,那么这里6就跳了两回了,多了好多重复操作,不过我们可以从后往前遍历,那么可以相当于记忆化,跳一次足够了。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 10;
ll a[maxn], dp[maxn]; // dp[i]就是从i位置开始跳出n需要加的权值
int main(){
int t; cin >> t;
while(t --){
int n; scanf("%d",&n);
for(int i = 1; i <= n; i ++){
scanf("%lld", &a[i]);
}
for(int i = 1; i <= n; i ++) dp[i] = 0;
ll ans = 0;
for(int i = n; i >= 1; i --){
ll d = i + a[i];
dp[i] += a[i] + (d <= n ? dp[d] : 0);
ans = max(ans, dp[i]);
}
cout << ans << endl;
}
return 0;
}
D. Even-Odd Game
题目大意
n个石子,两个人轮流取,取完为止。Alice先取,Bob后取。
如果Alice取的石头的重量wi为偶数,那么她的分数就会加wi,否则不加;
如果Bob取的石头的重量wi为奇数,那么他的分数就会加wi,否则不加。
问最后谁赢或者平局。
思路
要我选,肯定每次选最重的呀,能加分最好,如果我加不了分,那肯定是你加分了呀,不行,不能给你加,取他。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 10;
ll a[maxn];
int main(){
int t; cin >> t;
while(t --){
int n, x; cin >> n;
ll t1 = 0, t2 = 0;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
sort(a + 1, a + n + 1, greater<int>()); //从大到小排序
for(int i = 1; i <= n; i ++){
if(i % 2 == 1 && a[i] % 2 == 0) t1 += a[i]; //Alice先手 偶数加分
if(i % 2 == 0 && a[i] % 2 == 1) t2 += a[i]; //Bob后手 奇数加分
}
if(t1 > t2) puts("Alice");
else if(t1 < t2) puts("Bob");
else puts("Tie");
}
return 0;
}
E. Correct Placement
题目大意
n个孩子 排队拍照,每个孩子都有长宽属性wi,hi,如果i要排在j的前面,那么必须得满足wi<wj&&hi<hj或者wi<hj&&hi<wj.
现在问对于每个孩子i,输出一个可以排在他前面的孩子的下标(任意),如果不存在,则输出-1
思路
首先,如果规定wi是(wi,hi)之中的较小值,hi是(wi,hi)之中的较大值,那么只需要看是否满足wi<wj&&hi<hj这个条件即可
然后可以按照先wi后hi排序,保证左边w小于等于右边的w;
双指针的思想,i,j。i遍历数组,j追逐,如果a[j].w<a[i].w的话那么tmp就更新a[j].h的最小值, id是更新最小值的位置,如果此时tmp<a[i].h的话,那么此时id位置的这个小孩可以站在a[i].id这个孩子前面啦。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & (-x)
#define pp pair<int, int>
const int maxn = 2e5 + 10;
struct node{
int x, y, id;
bool operator < (const node &a) const{
if(x != a.x) return x < a.x;
return y < a.y;
}
}a[maxn];
int dp[maxn];
int main(){
int t, n;
cin >> t;
while(t --){
cin >> n;
for(int i = 1; i <= n; i ++){
cin >> a[i].x >> a[i].y;
if(a[i].x > a[i].y) swap(a[i].x, a[i].y);
a[i].id = i; dp[i] = -1;
}
sort(a + 1, a + n + 1);
int tmp = 0x3f3f3f3f, id = -1, j = 1;
for(int i = 1; i <= n; i ++){
while(j < i && a[j].x < a[i].x){
if(tmp > a[j].y){
tmp = a[j].y;
id = a[j].id;
} j ++;
}
if(tmp < a[i].y) dp[a[i].id] = id;
}
for(int i = 1; i <= n; i ++){
if(i > 1) cout << " ";
cout << dp[i];
}
cout << endl;
}
return 0;
}