算法训练#11:思维题之Strange_Table和 GCD_Sum

36 阅读1分钟

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

第一题

Strange Table

内容理解

有一个nnmm列的矩阵,里面是从11n×mn\times m的整数以镜像的“N”字型排列(也就是先从上到下排,再从左到右排),要求在找到数x在矩阵中的位置后,把矩阵的中的数的排列方式改变,以“Z”字型排列(也就是先从左到右排,再从上到下排),再找出刚刚哪个位置的对应数字是什么

输入

整数tt,表示输入的案例个数,1t100001\le t \le 10000
案例的第一行输入整数nnmmxx,其中0xn×m,0n,m1060\le x\le n\times m,0\le n,m \le 10^6

输出

输出tt个案例的结果,每个结果输出对应的整数

思路

最最暴力的思路那就是:用两种排列方式把两个矩阵生成出来,在第一个矩阵找到这个数的坐标,然后就把第二个矩阵对应坐标的数直接输出。这样的思路其实不大好,因为如果真的把矩阵弄出来,然后在矩阵中找的话,循环会消耗大量的时间复杂度,导致超时。其实我们可以细想一下,在生成矩阵时,矩阵的值与横坐标和纵坐标是不是存在着线性关系,通俗点讲,就是去找两个矩阵的规律,其实很容易找,一个是矩阵的值=纵坐标×m+横坐标+1矩阵的值=纵坐标\times m+横坐标+1,另一个是矩阵的值=横坐标×n+纵坐标+1矩阵的值=横坐标\times n+纵坐标+1。那解题就是简单的输入->基础运算->输出了。

代码

import java.util.Scanner;

public class Strange_Table {
    public static void main(String args[])
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++)
        {
            long n= sc.nextLong();
            long m=sc.nextLong();
            long x=sc.nextLong();
            long column;
            long row;
            row=x%n;
            if(x%n ==0) {
                column = x / n;
                row=n;
            }
            else
                column=x/n+1;
            long answer=row*m-m+column;
            System.out.println(answer);
        }
    }
}

第二题

GCD_Sum

内容理解

给出一个整数,求出它的数位和,然后再求出这个数和其数位和的最大公因数

输入

整数tt,表示输入的案例个数,1t100001\le t \le 10000
案例的第一行输入整数nn,其中1n10181\le n\le 10^{18}

输出

输出tt个案例的结果,每个结果输出对应的整数

思路

这里思路已经在题目里给出来了,我们要做的就是优化思路中复杂的过程,让它不要超时就行。这里求数位和的步骤是肯定不会超时的,那么我们就要看看如何在求公因数这里优化。最简单的求公因数的方法就是枚举法:定一个循环,从2开始遍历,找到这俩数都可以整除的就作为一个公因数,然后把这些公因数相乘就是最大公因数。但是这样的方法太慢了,我们要去用其他的方法。其他求公因数的方法有:辗转相除法,更相损减法等,都比前述的枚举法要快,所以用其中一种更快的方法就可以了。

import java.util.*;
public class GCD_Sum {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        //这里要注意一个点:读取输入的时候,nextInt()方法读取不了超出10位字符的整数,要用nextLong()才可以
        for (int i = 0; i < t; i++) {
            long n=sc.nextLong();
            long x=n;
            long sum=0;
            long ans =gcdSum(n);
            System.out.println(ans);
        }
    }
    public static long gcdSum(long n)
    {
        long x=n;
        long sum=0;
        while(x!=0)
        {
            sum+=x%10;
            x=x/10;
        }
        long z=div(n,sum);
        if(z>1)
            return n;
        else
            return gcdSum(++n);
    }
    //辗转相除求公因数
    public static long div(long a,long b){
        return a%b==0?b:div(b,a%b);
    }
    
}