Codeforces Round #512 (Div. 2, based on Technocup 2019 Elimination Round 1) A-E题解

本文深入解析了五道算法竞赛题目,包括寻找简单问题、Vasya与玉米地、Vasya与金票、Vasya与三角形及Vasya与优质序列,详细阐述了解题思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛传送门

A. In Search of an Easy Problem

最朴素的解法,扫一边有木有1。。。。。

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
	char c=getchar();num=0;int f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
	num*=f;
}
template<typename T> void qwq(T x){
	if(x>9)qwq(x/10);
	putchar(x%10+'0');
}
template<typename T> void write(T x){
	if(x<0){x=-x;putchar('-');}
	qwq(x);putchar('\n');
}
int container[110];

int main(){
	int n;read(n);
	rep(i,1,n){
			read(container[i]);
	}
	
	int nop=0;
	rep(i,1,n){
		if(container[i]==1){
			nop=1;
			break;
		}
	}
	
	if(nop==1){
		puts("HARD");
	}else{
		puts("EASY");
	}
	return 0;
}

B. Vasya and Cornfield

可以看出,在该矩形的所有点中,

0+d=d <=点的x坐标+点的y坐标<= n+(n-d)=2n-d;

0-d=-d<=点的x坐标-点的y坐标<=n-(n-d)=d;

依照以上规律判断即可

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int container[110][3];

int main(){
	int n,d,m;cin>>n>>d>>m;
	rep(i,1,m){
		cin>>container[i][1]>>container[i][2];
	}
	
	for(int i=1;i<=m;i++){
		int temp=container[i][1]+container[i][2];
		int nop=container[i][1]-container[i][2];
		if(d<=temp&&temp<=2*n-d&&-d<=nop&&nop<=d){
			puts("YES");
		}else{
			puts("NO");
		}
	}
	return 0;
}

C. Vasya and Golden Ticket

首先维护该数列的前缀和数组,在提取出所有总和的因数作为分割后可能的每个数列的和,

然后一波骚操作即可。

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
	char c=getchar();num=0;int f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
	num*=f;
}
template<typename T> void qwq(T x){
	if(x>9)qwq(x/10);
	putchar(x%10+'0');
}
template<typename T> void write(T x){
	if(x<0){x=-x;putchar('-');}
	qwq(x);putchar('\n');
}
int container[110];
int qz[110];
set<int>v;

int main(){
	int n;read(n);
	rep(i,1,n){
		char ch;cin>>ch;
		container[i]=ch-'0';
		qz[i]=qz[i-1]+container[i];
	}
	
	for(int i=1;i*i<=qz[n];i++){
		if(qz[n]%i==0){
			v.insert(i);v.insert(qz[n]/i);
		}
	}
	
	if(qz[n]==0){
		puts("YES");return 0;
	}
	v.erase(v.find(qz[n]));
	
	set<int>::iterator it;
	for(it=v.begin();it!=v.end();it++){
		int l=0;int nop=*it;bool flag=true;
		rep(i,1,n){
			if(qz[i]-qz[l]>nop){flag=false;break;}
			if(qz[i]-qz[l]==nop){
				l=i;
			}
		}
		if(flag==true){puts("YES");return 0;}
	}
	puts("NO");
	return 0;
}

D. Vasya and Triangle

首先,坐标系中的任何一个三角形,

其面积计算都可以看成是一个长高皆为整数,减去若干个底和高皆为整数的三角形的面积和。

所以目标三角形的面积只可能是整数,或一个整数+0.5,其他情况都不可能有解。

这一步判断完后,我们计算出三角形面积*2,再枚举底(总而算出高),

看底和高是否在规定范围内(注:光从1开始枚举会超时,需要优化循环次数)

#include<bits/stdc++.h>
#define ll long long
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
inline long long gcd(ll n,ll m){
	if(n%m==0)return m;
	return gcd(m,n%m);
}
set<int>v;

int main(){
	ll n,m,k;
	scanf("%lld%lld%lld",&n,&m,&k);
	
	ll temp1=n*m;ll temp2=k;
	ll temp3=gcd(temp1,temp2);
	temp1/=temp3;temp2/=temp3;
	if(temp2>2){
		puts("NO");
		return 0;
	}
	
	ll nop=n*m*2;nop/=k;
	
	ll start=min(nop/n,nop/m);
	bool flag=false;ll h=0;ll l=0;
	for(long long i=max(start,1ll);i*i<=nop;i++){
		if(i>n||i>m)break;
		if(nop%i==0){
			if(i<=n&&nop/i<=m){
				h=i;l=nop/i;
				flag=true;break;
			}
			if(i<=m&&nop/i<=n){
				h=nop/i;l=i;
				flag=true;break;
			}
		}
	} 
	
	if(flag==true){
		puts("YES");
	}else{
		puts("NO");return 0;
	}
	
	cout<<0<<" "<<0<<endl;
	cout<<h<<" "<<0<<endl;
	cout<<0<<" "<<l<<endl;
	return 0;
}

E. Vasya and Good Sequences

首先我们另外搞一个数组count,其中count[i]表示a[i]转成二进制后一的个数,

满足以下两个条件的区间[l,r]是一定符合要求的:

1:count[l]+count[l+1]......+count[r]是偶数。

2:max{count[l],count[l+1],......count[r]}*2<=count[l]+count[l+1]......+count[r]。

再搞一个数组sum,sum[0][i]表示区间[1,i]中x的个数,使得count[1]+count[2]+....count[x]是奇数,既不符合第一个条件。

sum[1][i]其实就=i-sum[0][i],既满足第一个条件的个数。

然后枚举每一个左端点,找出在[i,i+61](因为2^61>10^18,当时笔者没想到这点,就开大到了160)当中满足第二个条件的右端点的数量,再利用sum减去不符合第一个条件的数量。

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
	char c=getchar();num=0;long long f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
	num*=f;
}
long long container[300010];long long sum[2][300010];
int counts[300010];long long qz[300010];
inline void scz(int n){
	rep(i,1,n){
		long long temp=container[i];int gs=0;
		while(temp){
			gs++;
			temp-=(temp&(-temp)); 
		}
		counts[i]=gs;
	}
	return;
}

int main(){
	int n;read(n);
	rep(i,1,n){
		read(container[i]);
	}
	scz(n);
	rep(i,1,n){
		qz[i]=qz[i-1]+counts[i];
	}
	
	rep(i,1,n){
		sum[0][i]=sum[0][i-1];sum[1][i]=sum[1][i-1];
		if(qz[i]&1)sum[0][i]++;
		else sum[1][i]++;
	}

	long long ans=0;
	rep(i,1,n){
		int ll=i;int rr=min(ll+160,n);int temp1=0;long long temp2=0;
		rep(j,ll,rr){
			temp1=max(temp1,counts[j]);temp2+=counts[j];
			ans+=(temp1*2<=temp2&&temp2%2==0); 
		} 
		ll=rr+1;rr=n; 
		if(qz[i-1]&1)ans+=sum[0][rr]-sum[0][ll-1];
		else ans+=sum[1][rr]-sum[1][ll-1];
	} 
	printf("%lld\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值