百度之星2020初赛第一场 0719 题目3

Problem Description

初始有 a,b 两个正整数,每次可以从中选一个大于 1 的数减 1,最后两个都会减到 1,我们想知道在过程中两个数互质的次数最多是多少。

Input

第一行一个正整数 test(1≤test≤1000000) 表示数据组数。

接下来 test 行,每行两个正整数 a,b(1≤a,b≤1000)。

Output

对于每组数据,一行一个整数表示答案。

Sample Input

1
2 3

Sample Output

4

样例解释
2 3 -> 1 3 -> 1 2 -> 1 1

 

思路:

记忆化递归,

递归出口ans[1][i]=ans[i][1]=i

递推式

ans[i][j] = max(ans[i - 1][j], ans[i][j - 1]) + (int)B[i][j];

其中B[i][j]表示(i,j)是否互质。

用时375ms

Future Work:  在同数量级下做一点优化:考虑通过对称性减少一半的计算量。

#include
#include
#include
#include
using namespace std;
/*int gcd(int a, int b) {
	
	return a%b ? gcd(b, a%b) : b;
}
int rp(int a, int b) {
	bool flag = 0;
	if (a == 1 || b == 1)flag=1;
	if (gcd(a, b) == 1)flag = 1;
	return flag;
}*/
bool rp(int a, int b)
{
	if (a == 1 || b == 1)     // 两个正整数中,只有其中一个数值为1,两个正整数为互质数
		return true;
	while (1)
	{          // 求出两个正整数的最大公约数
		int t = a%b;
		if (t == 0)
		{
			break;
		}
		else
		{
			a = b;
			b = t;
		}
	}
	if (b>1)	return false;// 如果最大公约数大于1,表示两个正整数不互质
	else return true;	// 如果最大公约数等于1,表示两个正整数互质
}
bool B[1001][1001];
int ans[1001][1001];
int main() {
	for (int i = 1; i <= 1000; i++)
		for (int j = 1; j <= 1000; j++)
			B[i][j] = rp(i, j);
	for (int i = 1; i <= 1000; i++) {
		ans[1][i] = i;
		ans[i][1] = i;
	}
	for (int i = 2; i <= 1000; i++) {
		for (int j = 2; j <= 1000; j++) {
			ans[i][j] = max(ans[i - 1][j], ans[i][j - 1]) + (int)B[i][j];
		}
	}
	int test;
	int a, b;
	scanf("%d\n", &test);
	while (test--) {
		scanf("%d%d", &a,&b);
		printf("%d\n", ans[a][b]);
	}
	//system("pause");
	return 0;
}

 

你可能感兴趣的:(竞赛)