Codeforces Round #693 (Div. 3)ABCDE——解题报告

比赛链接:https://codeforces.com/contest/1472

A-Cards for Friends

题解

按照题意直接模拟就行,答案就是能 (被w乘除的最大的2的n次幂) 乘以 (被h乘除的最大的2的n次幂)。

判断是否大于等于n就行了。 

简单做法:巧妙利用二进制运算&处理,答案就是( w&(-w) )*( h&(-h) ),这个运算在树状数组中用的比较多。

麻烦做法:直接根据题意模拟即可。

代码

做法一

if(1ll*(w&(-w))*(h&(-h))>=n) puts("YES");
else puts("NO");

做法二

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 1e5+7;
int a[N];
void solve(){
	int w=read(),h=read();
	int n=read();
	ll cnt1=1,cnt2=1;
	ll cur=1;
	while(w%2==0){
		w/=2,cnt1+=cur,cur*=2;
		if(cnt1>=n){
			puts("YES");
			return ;
		}
	}
	cur=1;
	while(h%2==0){
		h/=2,cnt2+=cur,cur*=2;
		if(cnt1>=n){
			puts("YES");
			return ;
		}
	}
	if(cnt1*cnt2>=n) puts("YES");
	else puts("NO");
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	//time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

B-Fair Division

题解

题目给的范围很小,所以我们可以直接枚举1的个数和2的个数,然后判断存在当前组成的数是否和剩下的数相等即可。

也可以找规律

实际上,如果总和是偶数,并且至少有两个糖果的重量为1,那么答案始终是“Yes”(我们可以收集重量为2的糖果使得总重量尽可能接近一半的重量,然后添加重量为1的糖果)。

如果没有权重为1的糖果,则需要检查n是否为偶数(由于所有糖果的权重相同,因此只需要将它们分成两半即可)。

代码

做法一——枚举

rp(i,0,cnt1){
	rp(j,0,cnt2){
	    if(i+j*2==cnt1-i+(cnt2-j)*2){
	            puts("YES");
	 			return;
	 		}
	 	}
	 }
puts("NO");

做法二——规律

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
int a[107];
void solve(){
	int n=read();
	rp(i,1,n) a[i]=read();
	int cnt1=0,cnt2=0;
	rp(i,1,n){
		if(a[i]==1) cnt1++;
		else cnt2++;
	}
	int sum=cnt1+cnt2*2;
	if((sum%2==0&&cnt1>=2)||(n%2==0&&cnt1==0)) puts("YES");
	else puts("NO");
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	//time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

C-Long Jumps

题解

这个题有两个做法:dp记忆化或者逆序维护。

不难发现每个下标在第一次确定值后,在以后的其他下标进行操作时就不变了。

因此最直接的做法就来了,根据题意直接模拟就行,但是注意要记忆化一下(因为上面的那条性质),这样才不会超时。

当然也可以直接逆序维护,这个比较好写。

代码

做法一——逆序维护

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e6+7;
int a[N];
ll sum[N];
int vis[N];
int n;
void solve(){
	n=read();
	rp(i,1,n) sum[i]=0;
	rp(i,1,n) a[i]=read();
	RP(i,n,1){
		if(i+a[i]>n) sum[i]=a[i];
		else sum[i]=sum[i+a[i]]+a[i];
	}
	printf("%lld\n",*max_element(sum+1,sum+1+n));
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	//time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

做法二——记忆化搜索

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
int a[N];
ll sum[N];
int n;
int dfs(int index){
	if(index>n) return 0;
	if(sum[index]!=-1) return sum[index];
	// outval(index);
	return sum[index]=a[index]+dfs(index+a[index]);
}
void solve(){
	n=read();
	rp(i,1,n) sum[i]=-1;
	rp(i,1,n) a[i]=read();
	rp(i,1,n) if(sum[i]==-1) dfs(i);
	ll ans=0;rp(i,1,n) ans=max(ans,sum[i]);
	cout<<ans<<endl;
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	debug = 1;
#endif
	time_t beg, end;
	if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	return 0;
}

D-Even-Odd Game

题解

根据题意不难想到当轮到Alice时,肯定选择对他获益最大的,这里的获益不仅指Alice可以拿到的分数,也可以这是对Bob造成的伤害(即需要使得Bob获益最小),Bob的情况同理。

因此模拟整个游戏过程,当轮到某人时,某人选择对自己获益最大的操作即可,与此同时维护Alice和Bob的和就行了。

最后判断Alice和Bob能够取到的和的大小即可。

代码

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
	int n=read();
	vector<int> v1,v2;
	ll sum=0;
	rp(i,1,n){
		a[i]=read();
		if(a[i]&1) v2.p_b(a[i]);
		else v1.p_b(a[i]);
		sum+=a[i];
	}
	sort(v1.begin(),v1.end());
	sort(v2.begin(),v2.end());
	int f=1;
	int cnt=n;
	ll sum1=0,sum2=0;
	while(cnt>0){
		if(f){
			if(v2.size()>0&&v1.size()>0){
				if(v2[v2.size()-1]>v1[v1.size()-1]) v2.pop_back();
				else {
					sum1+=v1[v1.size()-1];
					v1.pop_back();
				}
			}
			else if(v1.size()>0) {
				sum1+=v1[v1.size()-1];
				v1.pop_back();
			}
			else v2.pop_back();
		}
		else{
			if(v2.size()>0&&v1.size()>0){
				if(v2[v2.size()-1]<v1[v1.size()-1]) v1.pop_back();
				else {
					sum2+=v2[v2.size()-1];
					v2.pop_back();
				}
			}
			else if(v2.size()>0) {
				sum2+=v2[v2.size()-1];
				v2.pop_back();
			}
			else v1.pop_back();
		}
		f^=1;
		cnt--;
	}
	// cout<<sum1<<" "<<sum2<<endl;
	if(sum1>sum2) puts("Alice");
	else if(sum1==sum2) puts("Tie");
	else puts("Bob");

}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	//time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

E-Correct Placement 

题解

大致理解题意后以为是一道二维偏序的题,仔细想了想没有那么麻烦,只需要维护个线段树(或者维护前缀最小值下标数组)。

首先把每个人按照h进行排序,同时线段树维护区间w最小值和最小值下标。

这样就能先二分筛出来一批(h比当前h(或者w)小的人),

然后每次操作时,用线段树查询这批人里面的最小的w,判断这个最小的w是否比当前w(或者h)小,如果小的话,则表示这批人里面w最小的那个人可以站在现在这个人前面,记录下标即可。

代码

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
struct node{
	int w,h,id;
	bool operator < (const struct node b)const{
		return (*this).h<b.h;
	}
}p[N];
int ans1[N],ans2[N];
ll a[N];
struct edge
{
    int id;
    int left,right;
    ll min;
}num[N*4];
//建树
pair<int,ll> buildmin(int left,int right,int cnt)
{
    int mid;
    num[cnt].left=left;
    num[cnt].right=right;
    if(left==right)
    {
        num[cnt].id=left;
        num[cnt].min=p[left].w;
        return make_pair(left,p[left].w);
    }
    mid=(left+right)>>1;

    pair<int,ll> r1=buildmin(left,mid,cnt*2);
    pair<int,ll> r2=buildmin(mid+1,right,cnt*2+1);
    if(r1.second<r2.second)
    {
        num[cnt].id=r1.first;
        num[cnt].min=r1.second;
        return r1;
    }
    else
    {
        num[cnt].id=r2.first;
        num[cnt].min=r2.second;
        return r2;
    }
}
//返回pair类型,first为下标,second为最小值
pair<int,ll> querymin(int left,int right,int cnt)
{
    int mid;
    if(left==num[cnt].left&&right==num[cnt].right)
        return make_pair(num[cnt].id,num[cnt].min);
    mid=(num[cnt].left+num[cnt].right)>>1;

    if(right<=mid)
        return querymin(left,right,cnt*2);
    else if(left>mid)
        return querymin(left,right,cnt*2+1);
    else
    {
        pair<int,ll> r1=querymin(left,mid,cnt*2);
        pair<int,ll> r2=querymin(mid+1,right,cnt*2+1);
        return r1.second<r2.second?r1:r2;
    }
}
void solve(){
	int n=read();
	rp(i,1,n) p[i].h=read(),p[i].w=read(),p[i].id=i;
	rp(i,1,n) ans1[i]=ans2[i]=-1;
	sort(p+1,p+1+n);
	buildmin(1,n,1);
	rp(i,1,n){
		int id=lower_bound(p+1,p+1+n,node{0,p[i].h,0})-p;
		id--;
		if(id==0) continue;
		ll val=querymin(1,id,1).second;
		int Id=querymin(1,id,1).first;
		if(val<p[i].w) ans2[p[i].id]=p[Id].id;
	}
	rp(i,1,n){
		int id=lower_bound(p+1,p+1+n,node{0,p[i].w,0})-p;
		id--;
		if(id==0) continue;
		ll val=querymin(1,id,1).second;
		int Id=querymin(1,id,1).first;
		if(val<p[i].h) ans2[p[i].id]=p[Id].id;
	}
	rp(i,1,n){
		if(ans1[i]==-1&&ans2[i]==-1) printf("-1");
		else if(ans1[i]!=-1) printf("%d",ans1[i]);
		else printf("%d",ans2[i]);
		printf("%s",i==n?"\n":" ");
	}
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	//time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值