藍橋杯—演算法訓練

PamShao發表於2021-04-18

區間k大數查詢

問題描述

給定一個序列,每次詢問序列中第l個數到第r個數中第K大的數是哪個。

輸入格式

第一行包含一個數n,表示序列長度。

第二行包含n個正整數,表示給定的序列。

第三個包含一個正整數m,表示詢問個數。

接下來m行,每行三個數l,r,K,表示詢問序列從左往右第l個數到第r個數中,從大往小第K大的數是哪個。序列元素從1開始標號。

輸出格式
總共輸出m行,每行一個數,表示詢問的答案。

樣例輸入
5
1 2 3 4 5
2
1 5 2
2 3 2
樣例輸出
4
2

程式碼

#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//輸出 
void input(int* Num, int l, int r, int k)
{
	int i, j, * max, tmp, n = r - l+1, seq = l;
	max = (int*)calloc(n, sizeof(int));

	for (j = 0; j < n; j++)
	{
		max[j] = Num[seq++];
	}

	//氣泡排序
	for (i = 0; i < n; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			if (max[j] > max[i])
			{
				tmp = max[i];
				max[i] = max[j];
				max[j] = tmp;
			}
		}
	}
	printf("%d\n", max[k - 1]);
	free(max);
}


int main(int argc, char* argv[])
{

	int n, m, * l, * r, * K, * Num, i;

	scanf("%d", &n);

	//輸入數列 
	Num = (int*)calloc(n, sizeof(int));
	for (i = 0; i < n; i++)
	{
		scanf("%d", &Num[i]);
	}

	//輸入條件 
	scanf("%d", &m);
	l = (int*)calloc(m, sizeof(int));
	r = (int*)calloc(m, sizeof(int));
	K = (int*)calloc(m, sizeof(int));
	for (i = 0; i < m; i++)
	{
		scanf("%d %d %d", &l[i], &r[i], &K[i]);
	}

	//開始操作
	for (i = 0; i < m; i++)
	{
		input(Num, l[i] - 1, r[i] - 1, K[i]);
	}

	free(Num);
	free(l);
	free(r);
	free(K);
	system("pause");
	return 0;
}

最大最小公倍數

問題描述

已知一個正整數N,問從1~N中任選出三個數,他們的最小公倍數最大可以為多少。

輸入格式

輸入一個正整數N。

輸出格式
輸出一個整數,表示你找到的最小公倍數。

樣例輸入
9
樣例輸出
504

程式碼

方法1:

直接將所以的最小公倍數,存起來,再去找最小值,小點的數可以,大點的數就不行

#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//求最大公約數
int gcd(int a, int b)
{
	if (b == 0)
		return a;
	else
		return gcd(b, a % b);
}
//求最小公倍數=兩數之積/兩數最大公約數
int lcm(int a, int b)
{
	if (a * b == 0)
		return 0;
	return (a * b) / gcd(a, b);
}

int LCM_lcm(int a, int b, int c)
{
	int tmp;
	tmp = lcm(a, b); 
	tmp = lcm(tmp, c);
	return tmp;
}


int main(int argc, char* argv[])
{

	int n, i, j, k, * LCM, lcmMax, g = 0;

	scanf("%d", &n);
	LCM = (int*)calloc(n * n * n, sizeof(int));

	//將所有的最小公倍數存於陣列中 
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++)
		{
			for (k = 1; k <= n; k++)
			{
				LCM[g++] = LCM_lcm(i, j, k);
			}
		}
	}

	//找到最大值 
	lcmMax = LCM[0];
	for (i = 0; i < n * n * n; i++)
	{
		if (LCM[i] > lcmMax)
		{
			lcmMax = LCM[i];
		}
	}
	printf("%d\n", lcmMax);

	system("pause");
	return 0;
}

方法2:

參考:連結

首先,窮舉法不適用

然後,求三個正整數的最小公倍數不會大於這三個數的乘積

因為,兩個數互質時,它們的公倍數最大,即它們的乘積

那麼三個數時,就是三個數兩兩互質時,即它們的最小公倍數最大,就是它們的乘積

故需要滿足:

1.三個數兩兩互質

2.在滿足a的條件下,使得三個整數取最大值

那麼考慮N的取值:

a).N為奇數時

當N為奇數時,N - 1為偶數,N - 2為奇數,顯然,數學知識告訴我們,相鄰的兩個正整數互質。同樣的,相鄰的兩個奇數也是互質的,那麼此時題目要求的答案為N * (N - 1) * (N - 2)

b).N為偶數時

 因為當N >3時,N 和當N - 3是可能不是互質的,例如3和6。所以偶數時又分為兩種可能性:

  b1).當3不能整除N時

    當N為偶數時,N - 2同樣為偶數,那麼就不能滿足上面思路的第1點了。但是N和N - 1還是互質的,所以在貪心策略下,我們優先考慮使用更小的值去替換N - 2,而不是替換N 和 N - 1。

    經計算發現 N - 3滿足要求,所以此時答案為N * (N - 1) * (N - 3)【偶、奇、奇】

  b2). 當3能整除N時

     因為N能夠被3整除,所以N - 3同樣能被3整除,為了不違反第1點,我們再次優先用更小的值替代 N - 3

     因為採用的是貪心策略,所以我們優先考慮使用N - 1去替換N,此時結果是:(N - 1) * (N - 2) * ( N - 3)。
     顯然相鄰的兩個正整數是互質的,我們只要考慮N - 1和N - 3是否互質就可以了。
     因為N - 1和 N - 3實際上等同於第1種情況,即N為奇數時,故 (N - 1) * (N - 2) * ( N - 3)就是我們需要的點

程式碼

#include <stdio.h>

long long FindMax(long long N){
	long long res;       
	if(N <= 2)
		return N;
	
	if(N % 2 != 0){   //第一種情況,N為奇數時,最大最小公倍數為N * (N - 1) * (N - 2)
		res = N * (N - 1) * ( N - 2); 
	}
	else{
		if(N % 3 != 0)      //第二種情況 
			res = N *(N - 1) * (N - 3);
		else                   //第三種情況 
			res = (N - 1) * (N - 2)* (N - 3);
	}
	return res;
}

int main(){
	long long N;
	scanf("%lld",&N);
	printf("%lld",FindMax(N));
	return 0;
}

相關文章