codeforces round #702题解

A. Dense Array
题目大意:
给定一个数组,插入任意数字,要使数组的所有相邻两项满足,
在这里插入图片描述
那么最多需要进行多少次插入操作?
解析:贪心算法

#include<bits/stdc++.h>
using namespace std;
int a[100];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		scanf("%d",&n);
		for( int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		long long ans=0;
		for( int i=2;i<=n;i++){
			int small=min(a[i],a[i-1]);
			int big=max(a[i],a[i-1]);
			while(small*2<big){
				small*=2;
				ans++;
			}
		}
		printf("%lld\n",ans);
	}
}

B. Balanced Remainders
题目大意:
给定一个数组,将数组中的所有元素模3,要使数组其余1,余2,余0的个数相等,最少进行几次加一操作?
解析:模拟,余0的数加一就是余1的数,以此类推

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		int c0=0,c1=0,c2=0,temp;
		for( int i=1;i<=n;i++){
			scanf("%d",&temp);
			if(temp%3==0) c0++;
			else if(temp%3==1) c1++;
			else if(temp%3==2) c2++;
		}
		long long ans=0;
		if(c0>n/3){
			c1+=c0-n/3;
			ans+=c0-n/3;
			c0=n/3;
			if(c1>n/3){
				ans+=c1-n/3;
			}
			else{
				if(c1<n/3){
					ans+=2*(n/3-c1);
				}
			}
		}
		else if(c0<n/3){
			if(c1>n/3){
				ans+=c1-n/3;
				c2+=ans;
				ans+=n/3-c0;
			}
			else if(c1<n/3){
				ans+=2*n/3-2*c1+(n/3-c0);
			}
			else ans+=n/3-c0;
		}
		else if(c0==n/3){
			if(c1>c2) ans=n/3-c2;
			else ans=2*(n/3-c1);
		}
		printf("%lld\n",ans);
	}	
}

C. Sum of Cubes
题目大意:
给定x,判断x是否满足a3+b3==x(a,b>1)
注:x的最大值是1e12
解析:判断一个数x是否满足条件,如果使用暴力枚举,每个数需要n2的时间复杂度。进行优化,可以先将所有的立方数算出,共有1e4个,首先枚举a3,再用二分查找检验
x-a^3是否存在。可以使用STL set。

#include<bits/stdc++.h>
using namespace std;
set<long long >cube;
int main(){
	cube.clear();
	for(long long int i=1;i*i*i<=1e12;i++){
		cube.insert(i*i*i);
	}
	int t;
	cin>>t;
	while(t--){
		long long x;
		cin>>x;
		int flag=1;
		for(long long int i=1;i*i*i<=x;i++){
			if(cube.find(x-i*i*i)!=cube.end()){
			//check x-i^3 is in the set 
				flag=0;
				break;
			}
		}
		if(flag==0) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
}

D. Permutation Transformation
题目大意:给出一组二叉树的节点,大的为父节点,小的为子结点,父节点左侧的是左子树,父节点右侧的是右子树,按顺序输出每个节点的层数(父节点在第0层)。
解析:二叉树的递归遍历

#include<bits/stdc++.h>
using namespace std;
int a[110];
int ans[110];
int findmax(int l,int r){
	int maxx=0,temp;
	for(int  i=l;i<=r;i++){
		if(a[i]>maxx){
			maxx=a[i];
			temp=i;
		}
	}
	return temp;
}
void check(int l,int r,int floor){
	if(l>r)	return ;	
	int pos = findmax(l,r);
	ans[pos]=floor;
	check(l,pos-1,floor+1);
	check(pos+1,r,floor+1);
	return ;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for( int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		check(1,n,0);
		for(int i=1;i<=n;i++){
			printf("%d ",ans[i]);
		}
		cout<<endl;
	}
}

E. Accidental Victory
题目大意:
有n个人,每人有数个硬币,他们之间要进行n-1场比赛。对于每一场比赛,硬币多的人会拿走硬币少的人的所有硬币,最后有硬币的人称为winner。请问最后有几个人有可能称为winner?输出他们的序号。
解析:前缀和

#include<bits/stdc++.h>
using namespace std;
struct num{
	int pos,x;
};
num a[200100];
long long int f[200100];//前缀和数组,注意开long long 
int ans[200100];
int cmp( num a,num b){
	return a.x<b.x;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		memset( ans,0,sizeof(ans));
		for( int i=1;i<=n;i++){
			scanf("%d",&a[i].x);
			a[i].pos=i;
		}
		sort(a+1,a+1+n,cmp);
		for( int i=1;i<=n;i++){
			f[i]=a[i].x+f[i-1];
		}
		ans[a[n].pos]=1;
		int count=1;
		for( int i=n-1;i>=1;i--){
			if(f[i]>=a[i+1].x) 
			{
				ans[a[i].pos]=1;
				count++;
			}
			else break;
		}
		cout<<count<<endl;
		for( int i=1;i<=n;i++){
			if(ans[i]) printf("%d ",i);
		}
		cout<<endl;
	}
}

F. Equalize the Array
题目大意:
给定一个数组,数组中有n个数,现在让数组变成beautiful,意思是数组中的每个数只出现1次或者n次
解析:离散化+疑似dp

#include<bits/stdc++.h>
using namespace std;
int a[200100];
int b[200100];
int cmp(int a,int b){
	return a>b;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		sort(a+1,a+1+n);
		int temp=a[1],count=0,j=1;
		a[n+1]=-1;//处理边界点 
		for( int i=1;i<=n+1;i++){//离散化处理 
			if(temp==a[i]) count++;
			else{
				b[j]=count;
				j++;
				count=1;
				temp=a[i];
			}
		}
		sort(b+1,b+j,cmp);
		int ans=1e9,sum=0;
		for( int i=1;i<j;i++){
			sum+=b[i];
			ans=min(sum-b[i]*i,ans+b[i]);
		}
		cout<<ans<<endl;
	}
}

G. Old Floppy Drive
题目大意:不会写了,网上的答案。。。。。。
模拟,数学
题意为给出一列数,指针起始时位于下标1的位置,每隔一秒指针会向后移动一格并取走相应位置的数n往后走为1,要求求出对于给定的数x,指针至少走多久时间能够取得总和大于x的数或者永远取不到。
解析:首先考虑取不到的情况,即每次循环完一遍n个数,取得数的总和sum不增,并且在一个周期的过程中所取得数总和sum的最大值小于x。对a数组求一遍前缀和,条件即为a[n]<=0&&max(a[i])<x,i∈[1,n]。直接输出-1即可。
其余情况都可以取到x,先对数组a求一遍前缀和,再求出取得的数总和sum达到x-max(a[i])时所需的循环次数,最后一次遍历求出前缀和数列中第一个比x-sum大的数所在位置pos,这个地方我用线段树查询,直接遍历会超时,答案即为前面循环所耗费的次数加上pos,由于起始位置位于1,所以最后结果要再减一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值