Codeforces Round #693 (Div. 3) ABCDE题解
A. Cards for Friends
思路:
最多能折的次数为:\(2^{l_{1}+l_{2}}\),\(l_{1},l_{2}\)分别表示长宽能各折多少次
#include<iostream>
#include<stdio.h>
#include<bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
#define Mem(f, x) memset(f,x,sizeof(f))
using namespace std;
int main(){
int t;
cin>>t;
int a,b,h;
while(t--){
cin>>a>>b>>h;
int c=a*b,cnt=1;
while(!(c%2))c/=2,cnt*=2;
if(cnt>=h)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
B. Fair Division
思路:
- 若1的个数为奇数,不能均分
- 若1的个数是偶数,就继续看2的个数:如果2也是偶数,就能均分。但如果2的数量是奇数,说明有个人要多拿一个2,所以看均分好的1够不够每个人都大于等于1个,这个时候2多拿的那个人少拿一个1给另一个人即可
if(cnt1&1) cout<<"NO"<<endl;//奇数
else
{
if(cnt2&1)//奇数
{
if(cnt1>=2) cout<<"YES"<<endl;//可以均分
else cout<<"NO"<<endl;
}
else cout<<"YES"<<endl;//偶数
}
C. Long Jumps
思路:
dp[i] (从后往前计算)的含义:从后往前计算过程中在 i 处的所能积累的能够对之前产生的最大贡献量
计算过程类似dp,满足在计算过程中前面结果影响不会后面的结果,需要从后到前遍历$$d[i] = d[i+a[i]] + a[i]$$
#include<bits/stdc++.h>
#define LL long long
#define mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)
#define fo(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
using namespace std;
template<class T>inline void read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
}
int a[200005],dp[200005];
int main(){
int t;
read(t);
int n;
while(t--){
read(n);
fo(i,1,n)read(a[i]);
dp[n]=a[n];
int mx=a[n];
per(i,n-1,1){
int to=i+a[i];
if(to<=n)dp[i]=dp[to]+a[i];
else dp[i]=a[i];//也是有贡献的,别忘了
mx=max(mx,dp[i]);
}
cout<<mx<<endl;
}
return 0;
}
D. Even-Odd Game
思路:
贪心,首先想到的是有大拿大,先奇偶数分开排序。
然后如果是Alice回合(拿偶数round),我可以自己拿偶数加分或者拿掉对面最大的(奇数)让对手难受。,如果我当前最大比对方的最大要小,我就拿走对方的,这样我就算损失也可以尽可能小。反之就赶紧把自己大的这个拿走,不然对方会用同样招数来恶心你(Bob同理)
#include<bits/stdc++.h>
#define fo(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
typedef long long ll;
const int maxn = 2e5+200;
inline ll read(){
ll f = 1,x = 0;
char ch = getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}
while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();
return x*f;
}
ll odd[maxn];
ll even[maxn];
int main(){
int kase;
cin>>kase;
while(kase--){
ll n = read();
int p1 = 0,p2 = 0;
fo(i,1,n){
ll x = read();
if(x&1) odd[++p1] = x;
else even[++p2] = x;
}
sort(odd+1,odd+1+p1);
sort(even+1,even+1+p2);
ll a = 0,b = 0;
int cnt = 1;
while(p1>=1||p2>=1){
if(cnt&1){
if(p1>=1&&odd[p1]>even[p2]) p1--;
else a += even[p2--];
}
else{
if(p2>=1&&even[p2]>odd[p1]) p2--;
else b += odd[p1--];
}
cnt++;
}
if(a>b) cout<<"Alice"<<endl;
else if(a<b) cout<<"Bob"<<endl;
else cout<<"Tie"<<endl;
}
return 0;
}
E. Correct Placement
思路:
见代码,先对原二元组按照w从小到大排序,然后只需要顺序遍历一遍,因为前面的w肯定比当前的小,遍历的时候记录最小的h及其原下标即可,但是因为有重复的w存在,所以遇到后面还有w一样的要先判断完再更新
#include<bits/stdc++.h>
#define fo(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
typedef long long ll;
const int maxn = 2e5+200;
const int inf=0x3f3f3f3f;
inline ll read(){
ll f = 1,x = 0;
char ch = getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}
while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();
return x*f;
}
typedef struct Pos{
ll w,h,id;
bool operator < (const Pos &a) const{
if(w!=a.w)
return w<a.w;
return h<a.h;
}//从小到大:先w后h
}P;
P a[maxn];
ll Ans[maxn];
int main(){
int kase;
cin>>kase;
while(kase--){
ll n = read();
fo(i,1,n){
ll w = read(), h = read();
if(w>h) swap(w,h);//令w是较小的那一个
a[i].w = w; a[i].h = h; a[i].id = i;
}
sort(a+1,a+1+n);
ll mih = inf,miw = inf;
ll cur = 0;
fo(i,1,n){
if(a[i].h>mih&&a[i].w>miw) Ans[a[i].id] = cur;//如果可以直接用
else{//如果不可以
int p = i+1;
Ans[a[i].id] = -1;
//因为有重复的w存在,所以遇到后面还有w一样的要先判断完再更新
while(p<=n&&a[p].w==a[i].w){
if(a[p].w>miw&&a[p].h>mih) Ans[a[p].id] = cur;
else Ans[a[p].id] = -1;
p++;
}
cur = a[i].id;
mih = a[i].h;
miw = a[i].w;
i = p-1;
}
}
fo(i,1,n) cout<<Ans[i]<<' '; cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号