寒假山师训练赛第一场题解

目录

A

题意

给一个数n,把他拆成a,b并且满足n=a+b,然后a,b互为质数也就是两个数的最大公约数为1,并且要求b-a尽可能的小,也就是a和b接近

思路

让a,从n/2开始,然后遍历就行,算出来b为n-a,判断a,b是否互质,如果互质输出就行,如果不互质,a就减减,继续

代码

#include<iostream>
using namespace std;

bool isrp(int a, int b)
{
	if(a==1||b==1)     // 两个正整数中,只有其中一个数值为1,两个正整数为互质数
		return true;
	while(1)
    {          // 求出两个正整数的最大公约数
		int t = a%b;
		if(t == 0) 
        {
            break;
        }
		else
        {
			a = b;
			b = t;
		}
	}
	if(b>1)	return false;// 如果最大公约数大于1,表示两个正整数不互质
	else return true;	// 如果最大公约数等于1,表示两个正整数互质
}
int main()
{
	int n;
	cin>>n;
	for(int i=n/2;i>=1;i--)
	{
		int b=n-i;
		if(isrp(i,b))
		{
		
		 cout<<i<<" "<<b;
		 break;
	    }
		 
	}
	return 0;
}

B

题意

给你n个房子,然后给你k个人,意思是这n个房子有k个房子已经居住过了,k个人住哪k个房子是最不知道的
然后规定有邻居的就是优质房子,然后给你n和k的值问你优质房子的最大值和最小值

思路

首先k为0或者等于n时候最大值和最小值肯定都是0,然后当k>n/2时,每隔一个空放一个k肯定都能放满,剩下的都是优质房,所以最大值为n-k,如果k<n/2时,可以想象一下如果n尽可能的大,k尽可能的小,那么可以满足 每个k两边都是优质房,所以最大值为2k,但这样有的数值会使2k加k大于n了这样不符合意义,所以如果2k>n-k最大值得是n-k,小于时最大值为2k,只要k的值不为0最小值肯定是1,因为k可以从头并排着 只剩末尾一个优质房

代码

#include<iostream>
using namespace std;
int main()
{
	int maxn;
	int minn; 
	int n;int k;
	cin>>n>>k;
	if(k==n||k==0)
	{
		maxn=0;
		minn=0;
	}
	else
	{
		if(k>=n/2)
		{
			minn=1;
			maxn=n-k;
		}
		else
		{
			minn=1;
			if(2*k>n-k)
			 maxn=n-k;
			else
			 maxn=2*k;
	    }
	}
	cout<<minn<<" "<<maxn;
	return 0;
}

C

题意

本来安排了n架飞机,每架飞机有mi的重要度,第i架飞机的起飞时间原定为i,而现在在k时之前不能有任何飞机起飞,每个时间点只有1架飞机能起飞,损失被定义为(飞机现起飞时间-飞机原起飞时间)*该飞机的重要度.现在要求你排一张时间表,要求每架飞机都只能在原起飞时间及以后起飞,且使损失最小.还要保证原定i起飞的飞机要在i之后起飞

思路

这题显然是重要度越大的越先起飞好,因为:假设a>b , an+b(n+1)=(a+b)n+b (1) , a(n+1)+b*n=(a+b)*n+a (2).显然(1)>(2).,但是这题还得保证原定i起飞的飞机要在i之后(或者i)起飞,所以我们还不能全部把所有单位都ya在优先队列里,
我们先把原定1-k时间的单位压到优先队列,然后,再把k+1到n+k依次压进一边加进原定当时起飞的飞机,一边找到优先队列中的最大值即队顶元素,将它放在该位置,更新它的新的起飞时间.这样可以保证i时进来的飞机一定在i之后起飞.

代码

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct NODE
{
	int i,w;
	bool operator < (const NODE&a)const
	{
		return w<a.w;
	}//重载<运算法为了保证放入优先对列的时候是按w排序的 
}p[300010];
int main()
{
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	 {
	 	cin>>p[i].w;
	 	p[i].i=i;
	 }
	 priority_queue<NODE>q;
	 for(int i=1;i<=k;i++)
	  q.push(p[i]);
	 long long sum=0;
	 for(int i=k+1;i<=n+k;i++)
	 {
	 	if(i<=n)
	 	{
	 		q.push(p[i]);
	 	}
	 	NODE now=q.top();
	 	q.pop();
	 	sum+=(long long) (i-now.i)*now.w;
	 	p[now.i].i=i;
	 }
	 cout<<sum<<endl;
	 for(int i=1;i<=n;i++)
	  cout<<p[i].i<<" ";
	 return 0;
	 
}

E

题意

这题实际上就是一个拆数问题,给你n个数,两个人拆,第一个人先拆,如果轮到一个人拆的时候这个数为1也就是不能再继续拆了 那么这个人就输了,但是每个数也都是轮换着的,假设第一个数 是第二个不能拆了 他输了 ,第二个数就由他现在拆

思路

因为一个数字n,可以拆的次数为固定的n-1次,故而只要统计全部的可操作次数,看总和的奇偶性即可。

代码

#include<iostream>
using namespace std;
int main()
{
	int n;
	int temp;
	int sum=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	 {
	 	cin>>temp;
	 	sum+=temp-1;
	 	if(sum%2==0)
	 	 cout<<"2"<<endl; 
	 	else
	 	 cout<<"1"<<endl;
	 	
	 }
	 return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值