第四次全国大学生算法设计与编程挑战赛 交流是一件很酷的事情 ,观察火车 ,人们总是渴望最强大的力量 ,在靠近一点就会爆炸

简单题不说,特别难的也不会。

目录

题目:交流是一件很酷的事情

思路:

题目:观察火车

思路

题目:人们总是渴望最强大的力量

思路:

题目:在靠近一点就会爆炸

思路:


        

题目:交流是一件很酷的事情

思路:

一道并查集的题。不过是数据量很大,根据题意知我们需要在建立并查关系的时候先看看这两个点是否联通,不然建了关系也没用。那么就转换成了判断图中任意两点的连通性问题,最佳的方案还是并查集,因为并查集的复杂度是线性的。

我们首先去根据原图建立一个并查集合,用于把能联通的点放到同一个集合中。然后再去建立一个并查集,用于合并点的思想关系。在合并到时候首先根据之前建立的并查集判断是否联通,如果联通就去合并这两个点的思想,然后一遍维护一个cnt数组去记录集合中的点个数。这道题就做完了。

注意并查集中fa数组的初始化和cnt的初始化。然后还有很重要的一点是最后使用cnt数组时候要用find找祖先,千万别用fa!!!

        

        

题目:观察火车

        

思路

题意:输入一个n问有多少个值满足a^2-b^2(a>b,都是自然数) (1<=n<=10e7)
输入:
10
输出:
7  因为1=(1,0)  3=(2,1)  4=(2,0)  5=(3,2)  7=(4,3)  8=(3,1)  9=(5,4)

这道题就是数论的题,不难想到一个数m可以拆成(a-b)(a+b),其实(a-b)和(a+b)就是m的一对因子,不妨设为x和y。而a和b都是整数,这个条件也需要用上

则有:

a+b=x;

a-b=y;

x*y=m;

联立求解:a=(x+y)/2,b=(x-y)/2;

也就是对于一个数m,只要存在一对因数x,y就必然存在一对a,b,又因为a和b必须为整数。

所以x+y和x-y必须为偶数。

不难发现

偶数+偶数=偶数,偶数-偶数=偶数

奇数+奇数=偶数,奇数-奇数=偶数

得出x和y必须同时为偶数或者奇数。

也就是m必须存在一对同时为偶数或者为奇数的因数 

那么这句话等价于m是4的倍数,或者是一个奇数

        

#include <bits/stdc++.h>
using namespace std;
int main(){
	int res=0,n;
	cin>>n;
	for(int i=1;i<=n;i++){
		if(i%4==0||i%2!=0)res++;
	}
	cout<<res;
}

        

        

题目:人们总是渴望最强大的力量

思路:

手动给出参考样例,题上的太弱了:
6 3 4
20 20 10 10 10 10   输出:16.666667和4
6 3 4
10 10 10 10 10 10   输出:10.000000和35

        
第一个任务好处理,只需要排个序,拿走a件物品能获得最大威力值。

第二个任务需要考虑最后一个物品的重复个数,相当于从所有等价物品y中选出x件即C(x,y)。

但是有个坑,如果说所有已经拿走的物品都是一样的,那么我们就要枚举拿每种件的情况,全部相加!!!

#include <bits/stdc++.h>
using namespace std;//double的精度是15位,最大值为1e308
int n,l,r,a[55];
double ans;
int run1(int x){
	int y=0;
	for(int i=1;i<=n;i++)
		if(a[i]==a[l])y++;
	int i=1,up=1,down=1;
	while(i<=x){//计算C(x,y)
		up*=i;down*=y;
		y--;i++;
	}
	return down/up;
}
int run2(){
	int res=0;
	for(int i=l;i<=r;i++)
		if(a[i]==a[l])
		res+=run1(i);
	return res;
}
int main(){
	cin>>n>>l>>r;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+1+n);
	reverse(a+1,a+1+n);//排列成降序
	int mx=a[1],num=0;//mx是末尾的值,num是重复个数
	for(int i=1;i<=l;i++){
		ans+=a[i];
		if(mx==a[i]) num++;
		else mx=a[i],num=1;
	}
	ans=1.0*ans/l;//第一个答案
	if(num!=l){//取件个数不变
		printf("%.6f\n",ans);
		cout<<run1(num);
		return 0;
	}
	else{//物品全都一样,那么取件个数可变
		printf("%.6f\n",ans);
		cout<<run2();
		return 0;
	}
}

题目:在靠近一点就会爆炸

        

思路:

有点玄学。

就是要先从最小的区间开始找规律:区间为1和2,A都是必输的,因为不能去掉两端的蛋!

然后开始考虑其他区间长度的,首先要明确的是操作次数为奇数时候A必赢,偶数时候B必赢。

操作次数等于原始区间长度减去最终区间长度。那么操作次数的奇偶性就和原始区间和最终区间差值有关了,即两者同时为偶数或奇数,操作次数为偶数;两者一奇一偶时操作数为奇数。

原始区间长度奇偶性好说,最终区间的怎么求呢?如果两个端点值是不等的,那么最终的区间长度一定是偶数,否则一定是奇数。

怎么证我不会啊,反正,额数论这里的东西,多见不怪了就。代码就好写了。

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值