UPC 2020年春混合个人训练第十二场

5月7日晚上的题目中的G、F、A、E都不难,怪我脑子这两天不大行,可能平时难题遇到的多了,也有些怀疑自己了,直接题目就没看,或者不敢想了 !其实静心思考,还是可以做的。

问题 A: GCD
时间限制: 1 Sec 内存限制: 512 MB

题目描述
最大公约数GCD(a,b)是指a,b共有的因子中最大的那一个。比如说,GCD(12,18)=6,因为6既是12的因子,也是18的因子,而且不存在其他比6大的而且也是12,18的因子的数。
小明想知道如果给定n,m,对于1<=i<=n,GCD(i,m)的最大值是多少。

输入
第一行有两个用空格隔开的正整数n,m,含义见题目描述
输出
一行,只有一个整数,表示对于1<=i<=n,GCD(i,m)的最大值。
样例输入 Copy
【样例1】
4 6
【样例2】
5 10

样例输出 Copy
【样例1】
3
【样例2】
5

提示
样例1说明
可以按照GCD的定义求得GCD(1,6)=1 ;GCD(2,6)=2;GCD(3,6)=3;GCD(4,6)=2;所以答案为3
样例2说明
可以按照GCD的定义求得GCD(1,10)=1;GCD(2,10)=2;GCD(3,10)=1;GCD(4,10)=2;GCD(5,10)=5,所以答案为5

数据范围
对于60%的数据, 1<=n<=1000,1<=m<=1000
对于100%的数据,1<=n<=1e9,1<=m<=1e9

题解: 这题是找1~n 这几个数中和m的最大公约数,这个因子要尽可能满足:既是m的大因子,又是1~n 中某个数的大因子。因此,我们先打表(开一个数组记录),求出并保存m的所有因子,然后升序排列,用尽可能大的因子去和n比较(这里和n比较是因为:如果n>=m的话,1~n 中就会出现一个和m相等的数,m的大因子是固定不变的,所以这个数就是1~n 中的数和m的最大公约数,em…可以说成是一个 “逐渐降低预算,尽可能买到在预算之内的最有价值的商品” 的过程)

#include <bits/stdc++.h>
#define ll long long 
using namespace std;

ll n,m,t,a[100010];

int main(){
	cin>>n>>m;
	
	//记录下 m的所有因子
	for(ll i=1;i<=sqrt(m);i++)
		if(m%i==0){
			a[++t]=i;
			a[++t]=m/i;
		}
		
	//将 m的所有因子升序排列
	sort(a+1,a+1+t);
	
	//找匹配 n的 ,属于m的最大因子,找到即输出
	for(ll j=t;j>=1;j--)
		if(n>=a[j]){
			cout<<a[j];
			break;
		}
	
	return 0;
}

问题 F: read
时间限制: 1 Sec 内存限制: 128 MB

题目描述
Carol是一个爱学习的小朋友,他最近在读一本书,这本书的某些页十分晦涩难懂,需要阅读完另一页的内容才能完全理解。
而有些页则比较通俗易懂,阅读完当前页即可理解。
Carol是一个喜欢钻研的小朋友,他每天都会从这本书中页数最小的从未读过的一页开始读,读到完全理解这一页的内容为止。
例如对于当Carol某一天要读这本书的第a页时,这一页要求读完第b页才能理解,于是Carol又要去读第b页,而第b页要求读完第c页才能理解,于是Carol又要去读第c页,而第c页不需要读别的页就可以理解,或是需要读的页在之前已经读过了,最终Carol这一天读了a,b,c这三页内容。
Carol想知道自己需要花多少天才能读完这本书。
输入
第一行一个整数n,表示这本书有n页
第二行有n个正整数a1,a2,…,an,其中ai表示要读完第i页的内容要先读完第ai页的内容。(ai≥i)
输出
一个正整数,表示读完这本书需要的时间。
样例输入 Copy
【样例1】
6
1 3 3 5 6 6
【样例2】
10
3 4 3 4 8 7 8 10 10 10
样例输出 Copy
【样例1】
3
【样例2】
5
提示
样例1解释:
第一天Carol读了第一页,不需要再阅读其他页。
第二天Carol读了第二页,第二页要求读完第三页,于是他又读了第三页。
第三天Carol读了第四页,第四页要求读完第五页,第五页又要求读完第六页,于是他把这些页都读了。

样例2解释:
第一天Carol读了第1, 3页
第二天Carol读了第2, 4页
第三天Carol读了第5, 8, 10页
第四天Carol读了第6, 7页
第五天Carol读了第9页

对于20%的数据,ai=i
对于另外20%的数据,ai = min(i + 2, n)
对于所有数据,1≤n≤100000

题解: 这题就是判断a[i]和i的关系,如果不相等,就找到让i=a[i],再进行判断,否则计数+1…依此循环,找到a[i]==i就计数累加【但是在写的时候要注意一些细节,比如已经计数过的要标记一下,避免重复标记,当天读过的(也就是第i天本应读过的)也要进行标记,表示一个较为麻烦的任务的完成,也就是题目所说的(要先读完…才能读…)】

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
ll n,i,j,t,sum,a[100010];

int main()
{
    cin>>n;
    for(i=1;i<=n;i++) scanf("%lld",&a[i]);
    
    for(i=1;i<=n;i++){
        if(a[i]==0) continue; //先判断有没有读过
        j=i; //保证所有的 i都能进行一次判断,不漏情况
        while(1){
        	/*while(1):循环的条件永远为真,循环会一直执行下去。
			除非循环体中有跳出循环的语句,否则就是死循环。*/
            if(a[j]==j||a[j]==0){
                a[j]=0; break; 
				/*找到那个能完成的任务了,就标记那个任务,表示读过了跳出循环,计数 +1*/
            } 
            //还未找到的时候就一直找,相当于跳过若干个中间变量
            t=a[j]; 
			a[j]=0; 
            j=t;
        }
        sum++; //天数 +1 
    }
    cout<<sum;
    return 0;
}

问题 G: sequence
时间限制: 1 Sec 内存限制: 128 MB

题目描述
Francis最近在研究序列问题,他定义了这样一种操作:
如果序列中没有数, 则输出0
否则选择序列中最小的数,将它移出序列并输出它,再把序列中所有的数减去它的值Francis的序列中有n(n≤100000)个数,他要进行k(k≤100000)次操作,他想知道每次操作的输出,但是他发现这个问题太复杂了,于是他决定把问题交给你,让你帮他解决这个问题。
输入
第一行两个正整数n, k,表示序列有n个数,一共要进行k次操作
第二行n个整数a1,a2,a3…,an,分别表示序列中的n个数, 并且ai≤109
输出
n行,每行一个整数
第i行的整数表示第i次操作的输出
样例输入 Copy
【样例1】
5 5
4 7 8 10 3
【样例2】
2 5
1 4
样例输出 Copy
【样例1】
3
1
3
1
2
【样例2】
1
3
0
0
0
提示
样例1解释
初始序列4, 7, 8, 10, 3
第一次操作找到最小的数3,移出它并输出它,并让序列中所有的数减去3
序列变为1, 4, 5, 7
第二次操作找到最小的数1,移出它并输出它,并让序列中所有的数减去1
序列变为3, 4, 6
第三次操作找到最小的数3,移出它并输出它,并让序列中所有的数减去3
序列变为1, 3
第四次操作找到最小的数1,移出它并输出它,并让序列中所有的数减去1
序列变为2
第五次操作找到最小的数2,移出它并输出它,并让序列中所有的数减去2

样例2解释
初始序列1, 4
第一次操作找到最小的数1,移出它并输出它,并让序列中所有的数减去1
序列变为4
第二次操作找到最小的数4,移出它并输出它,并让序列中所有的数减去4
序列为空
后三次操作均输出0

对于p%的数据,n, k ≤ 100000 ∗ (p/100)

题解: 按照题意,标签应该是 “堆”,但也可以当做 “模拟”题来写。这题要求我们查找当前最小的数,所以此题在 sort 快排后,按照要求输出即可。k<=n时,除了第一个最小值直接输出,其他的都是输出它本身的值减去上一个输出值(最小值)的差值。若 k>n,则多输出 (k-n) 个0。【需要注意的是:这样做输出不能用 cout (太慢,会超时)。】

//G.模拟 (也可以用堆)
#include <bits/stdc++.h>
#define ll long long 
using namespace std;
ll n,k,i,a[100010];
int main(){
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	sort(a+1,a+1+n);
	printf("%lld\n",a[1]);
	if(k<=n){
		for(i=2;i<=k;i++) printf("%lld\n",a[i]-a[i-1]);
	}
	else if(k>n) {
		for(i=2;i<=n;i++) printf("%lld\n",a[i]-a[i-1]);
	    for(i=n+1;i<=k;i++) printf("0\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米莱虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值