2020-05-18 — 习题训练一

A Phoenix and Balance

题意:给定n个数,从1-n分别是2^1,2^2……2^n,然后把他们分成个数相同的2部分,问如何分才能使得a-b的绝对值最小

题解:  根据各个值可以发现2^n一定比前面的所有数字相加都大,就是2^n>2^n-1+2^n-2……2^1,所以把最大值给一边,然后从大到小把n/2的值给另外一边就行

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,n,sum1,sum2;
	cin>>t;
	while(t--){
		cin>>n;
		sum1=0;
		sum2=pow(2,n);
		for(int i=n/2;i<=n-1;i++){
			sum1+=pow(2,i);
		}
		for(int i=1;i<n/2;i++){
			sum2+=pow(2,i);
		}
		cout<<abs(sum1-sum2)<<endl;
	}
	return 0;
}

 BPhoenix and Beauty

题意:给定n个数,要求他们按顺序k个数相加都要相等,可以在中间添数字,如果没有办法使他们相等则输出-1(a1,a2,a3,a4,如果k=2的话就是a1+a2=a2+a3=a3+a4=a4)

题解:找周期吧,设他们有多少个不同的数为k1,如果k1>k,那么无论怎么加数字都不能成功输出-1,否则可以输出n个周期(比如n=4 k=3,就可以1 2 3 1 2 3 1 2 3 1 2 3)

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
int a[105],vis[105],c[105],cn;
int main() {
	int t,i,b,n,k,cnt,j;
	scanf("%d",&t);
	while(t--) {
		scanf("%d%d",&n,&k);
		for(i=1; i<=100; i++)vis[i]=0;
		for(i=1; i<=n; i++)scanf("%d",&a[i]),vis[a[i]]=1;
		cnt=0;
		for(i=1; i<=100; i++)			if(vis[i])cnt++;
		if(cnt>k) {
			printf("-1
");
			continue;
		}
		if(cnt<k)			for(i=1; i<=100; i++)				if(!vis[i]) {
					vis[i]=1,cnt++;
					if(cnt==k)break;
				}
		cn=0;
		for(i=1; i<=100; i++)			if(vis[i])c[++cn]=i;
		printf("%d
",n*k);
		for(i=1; i<=n; i++) 			for(j=1; j<=k; j++)printf("%d ",c[j]);
		printf("
");
	}
	return 0;
}

C - Road To Zero

 题意:给你x和y,你有2个方法一个是他们每个都减1花费a元或者使其中一个减1花费b元,问怎样使得花费最低。

题解:就是找出花费最低的一个方法,当x和y都不是0时,可以通过第一种方法把其中最小的变为0,然后再加上剩下的值,或者全部使用第二个方法,比较他们2个哪个方案最小(如果第一种方法小于第二种时,不能一直使用第二种,因为其中一个数为0时不能再一起-1 - ,-)

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
	int t;
	ll x,y;
	ll a,b;
	ll sum1,sum2,sum3;
	cin>>t;
	while(t--){
		cin>>x>>y;
		cin>>a>>b;
	//	if(b<=a){
		//	sum1=max(x,y)*b;
	//		cout<<sum1<<endl;
	//	}
		//else{一个数到0不能2个一起减 
		sum2=min(x,y)*b+(max(x,y)-min(x,y))*a;
		sum3=(x+y)*a;
		cout<<min(sum2,sum3)<<endl;	
	//	}
	}
	return 0;
} 

  

D - Binary Period

 题意:跟第二题类似,只不过只能01串,然后添加数字使得他们有周期,最后的序列长度要小于等于2*s

题解:如果序列只有相同的数,那肯定本身就有周期了是1,如果不相同,就一直0101排列就好(比如010,s的长度是3那就可以输出一个长度6的序列要有周期,直接输出010101就可)

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,l,flag;
	string a;
	cin>>t;
	while(t--){
		flag=0;
		cin>>a;
		l=a.size();
		for(int i=0;i<a.size()-1;i++){
			if(a[i]!=a[i+1]){
				flag=1;//有2个字符 
				break;
			}
		}
		if(flag==0){
			cout<<a<<endl;
		}
		else{
			for(int i=0;i<l;i++){
				cout<<"1"<<"0";
			}
			cout<<endl;
		}
	}
	return 0;
} 

  

E - Nastya and Rice

 题意:

给你一个一袋米重量的范围和其中每一粒米的重量范围,问n个这些米是否在这个范围内

题解:

就是如果最大的重量*n<一袋米的重量或者最小的重量*n>一袋米的重量就不符合

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	int n,a,b,c,d;
	int flag;
	cin>>t;
	while(t--){
		flag=0;
		cin>>n>>a>>b>>c>>d;
		if(n*(a-b)>c+d){
			flag=1;
		}
		if(n*(a+b)<c-d){
			flag=1;
		}
		if(flag==1){
			cout<<"No"<<endl;
		}
		else{
			cout<<"Yes"<<endl;
		}
	}
	return 0;
} 

  

F - Nastya and Door

 题意:

给定一个序列,如果其中一个数大于左边且大于右边就能把他们分开(an>an-1&&an>an+1)然后再取一个k为从这个序列取k的长度,问哪一个取法能把他们分得最开

题解:

一开始看半天没看懂。。。然后其实可以用前缀和做,把i-1中有峰值记录下来,然后根据给定的长度算出a[i+k]-a[k],看哪边的峰值最多输出就好,题目有个坑,如果i和i+k是峰值,那a[i+k]-a[i]=0的,就是本身使不能算,后面一个值才能+1

代码:

#include<bits/stdc++.h>
using namespace std;
int f[200005];
int main()
{
    int t;
    scanf("%d",&t);
    int n,k;
    int fr1,fr2;
    int fr3;
    int ans;
    int l=1;
    while(t--)
    {
        memset(f,0,sizeof(f));
        scanf("%d%d",&n,&k);
        scanf("%d%d",&fr1,&fr2);
        for(int i=3;i<=n;i++)
        {
            scanf("%d",&fr3);
            if(fr2>fr1&&fr2>fr3) f[i]=f[i-1]+1;
            else
            {
                f[i]=f[i-1];
            }
            fr1=fr2;
            fr2=fr3;
        }
        ans=0;
        l=1;
        for(int i=k;i<=n;i++)
        {
            if(ans<f[i]-f[i-k+2])
            {
                ans=f[i]-f[i-k+2];
                l=i-k+1;
            }
        }
        printf("%d %d
",ans+1,l);
    }
    return 0;
}

  

   
   
原文地址:https://www.cnblogs.com/liyongqi/p/12925248.html