其他分享
首页 > 其他分享> > 20200314上机笔记

20200314上机笔记

作者:互联网

1 两个整数的除数 (100分)

给你一个混排的数列,其中包含x的所有除数(包括1和x)和y的所有除数(包括1和y)。如果d同时是x和y的除数,则列表中d将会出现两次。

例如,x = 4,y = 6,则给定列表可以是列表[1,2,4,1,2,3,6]的任何排列。一些可能的列表是:[1,1,2,4,6,3,2],[4,6,1,1,2,3,2]或[1,6,3,2,4,1,2]。

现在给定一个数列,它是某两个正整数x和y的所有除数列表。请你帮忙找出这两个正整数x和y。

输入格式:
第一行包含一个整数n(2≤n≤128),表示数列包含的数的个数。
第二行包含n个整数d1,d2,…,dn(1≤di≤10^4),其中di是x的除数或y的除数。如果一个数字同时是x和y的除数,则数组中有两个该数字。
输入保证答案存在。
输出格式:
输出仅一行,包含两个正整数x和y (x>=y),以空格分隔。

输入样例:
10
10 2 8 1 2 4 1 20 4 5

输出样例:
20 8

分析

1、由于该数列其中包含x的所有除数(包括1和x)和y的所有除数(包括1和y),且x>y,所以该数列中的最大值即为x。
2、把x的所有除数从数组中抽出,剩下的最大值就是y。

进行剔除x的除数

其中若同一个书出现两次,即另一个为y的除数,此时只能提出两个相同数中的一个

    for (i=0;;i++){
		if (a[n-1]%a[i]==0){
			if (a[i]==a[i+1]){
				continue;
			}
			k++;
			if (a[i]==t) break;
			for (j=i;j<n-k;j++){
				a[j]=a[j+1];
			}
			i--;
		}
	}

特判

排序后最后面的两个数相等,即最大的两个数相等,则x=y=最大数

    if (a[n-1]==a[n-2]){
		printf("%d %d",a[n-1],a[n-2]);
		return 0;
	} 

总代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int cmp(const void *a ,const void *b)
{
	return *(int *)a - *(int *)b ;		
} 
int main(){
	int n;
	int a[10007],b[10007],c[10007];
	int i,j,k=0;
	scanf("%d",&n);
	for (i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	qsort(a,n,sizeof(a[0]),cmp);
	if (a[n-1]==a[n-2]){
		printf("%d %d",a[n-1],a[n-2]);
		return 0;
	} 
	int t=a[n-1];
	for (i=0;;i++){
		if (a[n-1]%a[i]==0){
			if (a[i]==a[i+1]){
				continue;
			}
			k++;
			if (a[i]==t) break;
			for (j=i;j<n-k;j++){
				a[j]=a[j+1];
			}
			i--;
		}
	}
	int temp=0;
	int x=t,y=a[n-k-1];
	printf("%d %d",x,y);
	return 0;
}

2 出色的物理引擎 (100分)

卡罗拉最近沉迷于ark游戏,游戏中的地图上有n个浮空的石头围成了一圈,在优秀的物理引擎支持下,这些石头会自动落下。她发现石头落下的顺序是有规律的。一共有n个石头,从第一块石头开始数,数到第m个石头,那块就是第一个落下的石头;之后从第一个落下的石头后一个重新从1开始数,同样数到第m个石头,那个就是第二个落下的石头;以此类推。为了方便,对这些石头从1开始编号。卡罗拉现在想知道最后落下的是那一块石头?

输入格式:
输入包含两个整数n和m (1<=m,n<=1000)。

输出格式:
输出一 个整数,代表最后落下的石头的编号。

输入样例:
10 3

输出样例:
4

这是一个很典型的约瑟夫环问题,恰好之前做过一题类似的,现在就先不总结这题了,准备过段时间有空整理一篇专门约瑟夫环的问题,这题就一起放那里分析了

3 开机方案 (100分)

h学长有个机器用来完成任务。现在有n个任务,第i个任务(1<= i <= n)在ti时刻开始,并在ti + 1时刻结束。同一时刻不会有多个任务。 h学长可以在任何时刻开启机器,不过每一次开启机器都会消耗1点能量。h学长只有k点能量可以用于开启机器。但是机器开着的时候需要消耗燃料,显然让机器一直开着并不一定是最好的选择。现在h学长想利用自己具备的k点能量,有效的控制机器的开启,使得机器完成n个任务消耗的燃料尽可能的少。那么对应给出的n个任务以及h学长拥有的能量数,你能帮帮他吗? 提示:消耗的燃料要尽可能的少,即机器工作的时间尽可能的短。

输入格式:
第一行包括两个整数 n和k(1<= n <= 1e5, 1<= k <=n) ,表示有 n个任务和h学长拥有k点能量。

接下来 n行,每行一个整数ti(1<= ti <=1e9),表示第 i 个任务在ti 时刻开始,并在ti + 1时刻结束 。

输出格式:
输出一行包含一个整数,表示机器工作的最少时间。

输入样例1:
3 2
1
3
6

输出样例1:
4

样例1说明:

h学长有2点能量,可以用于两次机器的开启。 h学长会在时刻1 即第一个任务开始时开启机器,并在第二个任务结束时关闭机器; h学长会在时刻6 即第三个任务开始时开启机器,并在第三个任务结束时关闭机器。 机器总工作时间为 (4-1)+(7-6)=4 。

输入样例2:
10 5
1
2
5
6
8
11
13
15
16
20

输出样例2:
12

样例2说明: h学长有5点能量,可以用于5次机器的开启。 h学长会在时刻1 即第1个任务开始时开启机器,并在第2个任务结束时刻3关闭机器; h学长会在时刻5 即第3个任务开始时开启机器,并在第4个任务结束时刻7关闭机器; h学长会在时刻8 即第5个任务开始时开启机器,并在第5个任务结束时刻9关闭机器; h学长会在时刻11 即第6个任务开始时开启机器,并在第9个任务结束时刻17关闭机器; h学长会在时刻20 即第10个任务开始时开启机器,并在第10个任务结束时刻21关闭机器; 机器总工作时间为 (3-1)+(7-5)+(9-8)+(17-11)+(21-20)=12 。 开机、关机时刻不唯一。

分析

1、首先是要对间隔排序,把重新开机的机会用在间隔大的时候
2、由于执行任务的时间已经确定,无法改变任务的执行顺序,所以可以采用整体法,先算出如果一开始就开机直到任务结束的时间,然后再减去(k-1)次间隔(被减去的间隔为最大的前k-1次间隔,通过排序可实现)刚开始一直在执着于如何按顺序执行,还好得到一位很厉害的好朋友指点,感谢一波。

直接上代码吧,感觉分析到这里思路已经很清晰了

还是补充个注意点,数组一定要开的足够大,注意下数据范围,不然在PTA中提交会显示段错误

#include<stdio.h>
#include<stdlib.h>
int cmp(const void *a ,const void *b)
{
	return *(int *)b - *(int *)a ;		
} 
int main(){
	int n,k;
	scanf("%d %d",&n,&k);
	int i,j=0,m;
	int a[100007],b[100007];
	for (i=0;i<n;i++){
		scanf("%d",&a[i]);
		if (i!=0){
			b[j]=a[i]-a[i-1]-1;
			j++;
		}
	}
	qsort(b,j,sizeof(b[0]),cmp);
	int time=a[n-1]-a[0]+1;
	for (i=0;i<k-1;i++){
		time-=b[i];
	}
	printf("%d",time);
	return 0;
} 

6 下次一定(续)||poj1019

本题解法主要参考http://user.qzone.qq.com/289065406/blog/1301527312 该作者讲解的十分详细,十分感谢

你是一个bilibili的六级号,由于经常一键三连,所以一个硬币都没有,现在你又做了个梦,在梦中你制定了一个硬币增加规则:
第一天登陆后硬币总数1个,第二天登陆后硬币总数112个,第三天登陆硬币总数112123个......,以此类推,梦中不知日月,你瞬间拥有了11212312341234512345612345671234567812345678912345678910123456789101112345678910......无穷多个硬币。
常年维护B站秩序的百漂怪看不下去了,决定随机挑一个数x,作为这个无穷数的第x位,如果你能正确答对这第x位上的数是什么,就赠送给你与这个数等量的硬币。
百漂怪总共会挑t次。
你决定编程模拟一下,搏一搏,单车变摩托。
输入格式:
第一行包含一个正整数t(1≤t≤10),表示百漂怪挑了t次。 接下来t行,每行一个正整数x (1 ≤ x≤ 2^31-1),表示第i次,百漂怪挑的是第x位。
输出格式:
输出共t行,每行输出对应第x位上的数。
输入样例1:
2
3
8
输出样例1:
2
2
输入样例2:
6
222
66666
99999999
66656565
22222
2
输出样例2:
6
4
9
4
1
1

分析

1、进行打表,构造两个数组,a[i]代表第i组数据的长度,s[i]代表前i组数据的长度;例如 1 12 123 1234 12345分别为第1、2、3、4、5组
2、较强技巧性的数学运算

较强技巧性的数学运算

1、

for (i=2;i<size;i++){
		a[i]=a[i-1]+(int)log10((double)i)+1;
		s[i]=s[i-1]+a[i]; 
	}

2、

for (i=1;len<pos;i++){
		len+=(int)log10((double)i)+1;
	}
    return (i-1)/(int)pow((double)10,len-pos)%10;

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define size 31269
unsigned a[size],s[size];
void play_table(){
	//a[i]代表第i组数据的长度,s[i]代表前i组数据的长度;
	//例如 1 12 123 1234 12345分别为第1、2、3、4、5组
	a[1]=1;s[1]=1;
	int i;
	for (i=2;i<size;i++){
		a[i]=a[i-1]+(int)log10((double)i)+1;
		s[i]=s[i-1]+a[i]; 
	}
	return ;
}
int compute(int n){
	int i=1;
	while(s[i]<n){
		i++;
	}
	int pos=n-s[i-1];
	i=1;
	int len=0;
	for (i=1;len<pos;i++){
		len+=(int)log10((double)i)+1;
	}
    return (i-1)/(int)pow((double)10,len-pos)%10;
}
int main(){
	play_table();
	int t,x,sum;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&x);
		sum=compute(x);
		printf("%d\n",sum);
	}	
	return 0;
}

注意,在定义a[size],s[size]数组时要使用unsigned,若使用int会又部分数据超出

标签:20200314,上机,int,样例,笔记,学长,任务,机器,除数
来源: https://www.cnblogs.com/xiao-qingjiang/p/12505139.html