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;
}

posted @ 2021-01-05 22:01  chenshunpeng  阅读(112)  评论(2)    收藏  举报