PTA 满足条件的数字有多少?(from 郑州大学

题面如上:

这道题思路很简单:a1是x的一个因数,x又是b1的一个因数,可以很轻易的得知,x的范围是在a1到b1之间,然后需要写一个最大公约数的函数,如下:

这里方法有很多,就不一一列举了,然后通过判断

measure( x,a0)==a1和 x/measure(x,b0)*b0==b1

(两个数的最小公倍数等于这两个相乘再除以两个数的最大公因数,我这里颠倒顺序是防止x*b0爆int,一点点小细节。。)

上述两个等式即可,但是有那么简单就好了,我们不出意料的TLE(运行超时)了,这也不难想到,如果a1是1,b1是2e9,一个一个枚举必然是超时的,这时候就要想办法优化了。

方法一:也是最容易想到的,x既然是a1的倍数,那么我们可以每次增加a1啊,

              但是,出现问题了,如果a1是1,每次增加1,明显还是不行。这个方法不行,pass。

方法二:看来要找藏在体面下更深的奥秘了,这里我就直接说了,我们知道x是b1的约数,那么可                 以枚举从a1到根号b1,然后每次判断要同时判断两个数 x和 b1/x,任意一个符合都要加                 一,当然二者相等就不用了。

这样这道题就解决了。

补充:如果x从a1开始不对,就从1开始。。。(PS:虽然我也不知道为啥从a1可是会被卡)。

注意:我在代码里是利用了measure(a,b)==k   等价于 measure(a/k,b/k)==1。

最后贴一下代码:

#include<bits/stdc++.h>
using namespace std;
int n;
inline int read()
{
	int X = 0; bool flag = 1; char ch = getchar();
	while (ch < '0' || ch>'9') { if (ch == '-') flag = 0; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { X = (X << 1) + (X << 3) + ch - '0'; ch = getchar(); }
	if (flag) return X;
	return ~(X - 1);
}
int measure(int x, int y)
{
	int z = y;
	while (x % y != 0)
	{
		z = x % y;
		x = y;
		y = z;
	}
	return z;
}
int main()
{
	//ios_base::sync_with_stdio(false);
	//cin.tie(nullptr);
	//cout.tie(nullptr);
	n = read();
	while (n--) {
		int a0, a1, b0, b1;
		a0 = read();
		a1 = read();
		b0 = read();
		b1 = read();
		int cut = 0;
		int p = a0 / a1;
		int q = b1 / b0;
		for (int i = a1; i * i<= b1; i++) {
			if (b1 % i == 0) {
				if (i % a1 == 0 && measure(p, i / a1) == 1 && measure(b1 / i, q) == 1)
					cut++;
				int y = b1 / i;
				if (i == y)
					continue;
				if (y % a1 == 0 && measure(p, y / a1) == 1 && measure(b1 / y, q) == 1)
					cut++;
			}
		}
		printf("%d\n", cut);
	}
	return 0;
}

上面用到了快读,只是为了提高速度,并不是关键,再贴一个简易版的代码:


#include<bits/stdc++.h>
using namespace std;
int n;
int measure(int x, int y)//求x和y的最大公约数,辗转相除法。
{
	int z = y;
	while (x % y != 0)
	{
		z = x % y;
		x = y;
		y = z;
	}
	return z;
}
int main()
{
	scanf_s("%d", &n);//scnaf_S是在vs里面的使用的,否则会报错,在其他地方可以直接使用scanf。
	while (n--) {
		int a0, a1, b0, b1;
		scanf_s("%d %d %d %d", &a0, &a1, &b0, &b1);
		int cut = 0;
		int p = a0 / a1;
		int q = b1 / b0;
		for (int i = 1; i * i<= b1; i++) {
			if (b1 % i == 0) //这一步是确定i是b1约数
			{
				if (i % a1 == 0 && measure(p, i / a1) == 1 && measure(b1 / i, q) == 1)
					cut++;
				int y = b1 / i;
				if (i == y)
					continue;
				if (y % a1 == 0 && measure(p, y / a1) == 1 && measure(b1 / y, q) == 1)
					cut++;
			}
		}
		printf("%d\n", cut);
	}
	return 0;
}

​

第一次写题解,如果对你有帮助可以点赞,收藏哦!

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值