算法训练#16:多找找规律——Exciting Bets和Find The Array

39 阅读3分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情

第一题

Exciting Bets

题目理解

给出两个整数aabb,可以对aabb执行以下操作:

  1. 两个数都增加1
  2. 两个数都减去1(只能在a,b>0a,b \gt 0时使用)

执行以下操作后的两个整数我们称为ccdd,要使ccdd的公因数最大,求出要达到这个结果要使用的最少操作步数

输入

输入整数tt,代表案例个数,1t5×1031\le t\le 5\times 10^{3}
每个案例输入两个整数aabb1a,b10181\le a,b\le 10^{18}

输出

每个案例输出两个整数,第一个代表所有aabb变成的xxyy的最大公因数的最大值,第二个代表达到这个结果要使用的最少操作步数

思路

一开始我就是想用暴力,想省事(抱着侥幸心理),但是结果肯定是不行的。那么我们又转到找规律的思路上去。在用暴力解的过程中,我发现那个最大公因数好像就是aabb的差的绝对值,那么情况就简单多了,我们就可以进行以下操作来进行判定:

  1. aabb的较小值赋到aa上,较大值赋到bb
  2. aabb的其中一个拿过来作为判定基准,这里我们使用bb(较小值),设aabb的差的绝对值为xx
  3. xx已经是bb的因数,则步数为0
  4. 否则,则需判断bb两边的xxn1n-1倍数和nn倍数(我们不需要知道n是多少),然后看bb到哪一边的步数少,就取哪一边的步数作为答案

代码

#include<stdio.h>
#define in long long
//这里用c++是因为Java在长整型的处理性能上不如c++,这题用逻辑和思路一模一样的java代码就是大样例超时
int main()
{
	in t;
	scanf("%lld",&t);
	while(t>0)
	{
		in a,b;
		scanf("%lld %lld",&a,&b);
		in x=a>b?a-b:b-a;//最大公因数
		in y;
		if(x==0||a-x==0||b-x==0)
		{
			y=0;
		}
		else
		{
			in d=x;
			in e=a>b?a:b;
			y=x-e>0?(x-e>e?e:x-e):(e%x>x-e%x?x-e%x:e%x);
		}
		printf("%lld %lld\n",x,y);
		t--;
	}
	return 0;
 } 

第二题

Find The Array

题目理解

给出一个整数ss,要求找出一个特殊数组,其和为ss,数组如下:

  1. 设数组为aa,其中元素为aia_{i},其取值有以下两种情况:
  2. aia_{i}等于1
  3. aia_{i}不等于1,但是数组中有取值为ai1a_{i}-1或者ai2a_{i}-2的元素

输入

输入整数tt,代表案例个数,1t5×1031\le t\le 5\times 10^{3}
每个案例输入一个整数ss1s5×1031\le s\le 5\times 10^{3}

输出

每个案例输出一个整数——代表找出的特殊数组的长度

思路

不知道其他人会不会被这个题目带偏,反正我是被带偏了,一开始以为要根据和去找符合要求的数组元素,然后再把数组长度输出,实际上这样会把问题想复杂,我们不妨采用逆向思维:采用一套数组元素取值的模板去求这个数组的某个范围的元素的和,例如一个等差数列an=1+(n1)×2a_n =1+(n-1)\times 2,若前nn项和刚好等于ss,那很省事,直接输出nn即可;若前nn项和大于ss,而前n1n-1项和小于ss,这里是能不能用这个方法的核心,因为我们用的等差数列的公差是2,那意味着我们可以对数组中的元素做出调整,比如说最大的元素减一,然后第二大的元素减一,这么一直减下去直到有一个元素是2为止都可以,这样并不会导致数组中的元素的取值不符合要求。所以我们最担心的符合要求的问题就这样迎刃而解。

import java.util.Scanner;

public class Find_the_Array {
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++)
        {
            int s=sc.nextInt();
            int n=1;
            int sum=1;
            int count=1;
            while(s>sum)
            {
                n=n+2;
                sum+=n;
                count++;
            }
            System.out.println(count);
        }
    }
}