西安 K、Last Defence【规律 类似辗转相除法】

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5057

题意:给你T个例子  然后每个例子两个数a 和 b  分别是s1   s2

然后有一个规则 si = 前两个si差的绝对值  (显然i >= 2)

输出不同si值的个数

列个样例  7 2 即继续 5  3  2  1  1  0  1  1  0  1  0   1  0

结论1:首先可以发现到0  之后  基本就会一直循环下去了   知道了结束条件 

那一开始就想  模拟 放set   最后统计set个数 不就好了 

然后a  b 范围是【0,1e18】

再想到了 一个极端的例子   1    1e18    那写下去不就是  (1e18    -   1)     1       (1e18   -  2)    (1e18  -   3)    1    。。。。。

起码1e18  +   1个数  次     而1s跑  1e8    题目3s  肯定爆炸

我们以 7  4 为样例   7 4  3  1   2  1   1   0  

蓝色是减去的

可以发现  减去的4的个数有1个   3个数有1个  1个数是2个

即7/4 =  1个         4/3  = 1个      3/1 = 3个

7 - 4 = 3       4-3 = 1     3-1=2      3-1-1= 1    3-1-1-1=0

发现了什么3 1 2  0 就是我们要的那些数   怎么求个数也已经知道了 就是 a /  b  然后就取模 继续操作

不太对 刚刚说1个的个数 是2个 

为什么这样   因为  最后必定会出现一组  数 - num1 = num2   而num1 == num2   这就重复了   如上面的2-1=1

所以先记住 会重复一个   res--

一开始不是还有a b两个数吗  所以要加上

特殊:如果a  b 只有一个0    ans = 2个 (0和另一个不是0的数)

若0 0   ans = 1个(即只有0)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

long long solve(long long a, long long b){
	if (b == 0)
		return 0;
	long long ans = 0;
	ans += a / b + solve(b, a%b);
	return ans;
}
int main(){
	int t;
	scanf("%d", &t);
	for (int cas = 1; cas <= t; ++cas){
		long long a, b;
		scanf("%lld%lld", &a, &b);
		if (a == 0 && b || a && b == 0){
			printf("Case #%d: 2\n", cas);
			continue;
		}
		long long res = solve(max(a, b), min(a, b));
		res--;
		res += 2;
		printf("Case #%d: %lld\n", cas, res);
	}
	
	
	return 0;
} 

    

猜你喜欢

转载自blog.csdn.net/liangnimahanwei/article/details/82953642