某次周测趣题总结(数学篇)

T3

在这里插入图片描述

分析

  简单分析一下,该题本质上就是让求能将 n n n个分数全部以该进制下的有限小数形式表示出来的进制数,即对于题中所给的 n n n个十进制下的分数,让求最小的能将这 n n n个分数全部以有限小数形式表示出来的进制数。
  对于此题,我们可以换个角度考虑,即哪些分数可以用有限位数小数表示。首先,我们从十进制开始考虑1
  很容易想到,分数中决定是否能用有限位小数表示的只有它的分母2。所以,我们只用考虑所有能用有限位小数表示的分数的分母的特点就行了。
  对于一个· p p p进制小数,我们可以将其的十进制形式表示为
a n × p n + a n − 1 × p n − 1 + . . . + a 2 × p 2 + a 1 × p 1 + a 0 × p 0 + a − 1 × p − 1 + a − 2 × p − 2 + . . . + a − ( m − 1 ) × p − ( m − 1 ) + a − m × p − m a_n\times p^n+a_{n - 1}\times p^n - 1+ ... +a_2\times p^2+a_1\times p^1 +a_0\times p^0 +a_{_{-1}} \times p ^{-1} +a_{_{-2}}\times p ^{-2} +... + a_{_{-(m - 1)}}\times p^{-(m - 1)} + a_{_{-m}}\times p^{-m} an×pn+an1×pn1+...+a2×p2+a1×p1+a0×p0+a1×p1+a2×p2+...+a(m1)×p(m1)+am×pm
  因此,对于任意一个 n n n位的 p p p进制有限小数,该小数均可以表示为 p p p的倍数为分母的一个分数,同理可得对于任意一个分母为 p p p的十进制分数,均可以用一个进制数为 p p p的倍数的有限小数来表示。回归题目,可以猜想当进制数为所有给定分数的最简分数形式的分母的公倍数时,所有的已知分数可以用有限位小数表示。
  对于上述结论,依据算术基本定理,我们可以进一步得出对于分母的所有质因子的乘积 p r pr pr p r pr pr进制数也可以用有限位小数表示该分数3。而且对于整数进制数而言,该进制数一定是最小的。所以答案就是所有分数的最简分数形式的所有不同质因子的乘积。

实现

  该题的难点一部分在做法上,另一部分在实现方法上。首先,题目要求以 16 16 16进制数输出答案,所以进制转换是必不可少的。另一方面,该题数据量较大,需要考虑优化算法复杂度和算法精度。经检验,该题部分数据已无法用 l o n g long long l o n g long long表示,所以高精度算法是必须的。

code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include <set>

#define LL long long

using namespace std;

int top;

int f[100000000] , P[10000000] ;
long long num[10000000] , ans[1000000];//高精乘

char ch[100000000];//十六进制的答案

int gcd(int x , int y)//最大公约数(约分用)
{
	if(x > y)
		swap(x , y);
	return y % x ? gcd(y % x , x) : x;
}

void Prime(int n)//线性筛
{
	for(int i = 2 ; i <= n ; i++)
	{
		if(!f[i])
		{
			f[i] = i;
			P[top++] = i;
		}
		for(int j = 0 ; j < top && P[j] < n / i && P[j] <= f[i] ; j ++)
		{
			f[P[j] * i] = P[j]; 
		}
	}
}

void mul(int n)//高精度乘法(十六进制版)
{
	int len = strlen(ch);
	for(int i = len - 1 ; i >= 0 ; i --)//将字符串转换为数字数组以便计算
	{
		if('0' <= ch[i] && ch[i] <= '9')
			num[len - i - 1] = ch[i] - '0';
		else
			num[len - i - 1] = ch[i] - 'A' + 10;
	}
	for(int i = 0 ; i < len ; i ++)
	{
		ans[i] += num[i] * 1ll * n;
		num[i] = 0; 
		while(ans[i] > 15)
		{
			if(i == len - 1)
				len++;
			ans[i + 1] += ans[i] / ( 1ll * 16 );
			ans[i] %= 1ll * 16;
		}
	}
	for(int i = len - 1 ; i >= 0 ; i --)//将数字数组转换回字符串以便输出
	{
		
		if(ans[i] < 10)
			ch[len - i - 1] = ans[i] + '0';
		else
			ch[len - i - 1] = (ans[i] - 10) + 'A';
		ans[i] = 0;
	}
	ch[len] = '\0';
}
int main()
{
	int n;
	scanf("%d" , &n);
	set<int> prime;//去重用
	Prime(1000000);
	for(int i = 0 ; i < n ; i ++)
	{
		int x , y;
		scanf("%d%d" , &x , &y);
		int temp = gcd(x , y);
		x /= temp;
		y /= temp;//约分
		int e = sqrt(y);
		for(int i = 0 ; P[i] <= e ; i ++)//质因子分解(预处理优化)
		{
			if(!(y % P[i]))
			{
				prime.insert(P[i]);
				while(!(y % P[i]))
				{
					y /= P[i];
				}
			}
		}
		if(y > 1)
		{
			prime.insert(y);
		}
	}
	long long sum = 1;
	set<int>::iterator it;//迭代器
	ch[0] = '1';
	ch[1] = '\0';
	for(it=prime.begin(); it!=prime.end(); ++it)//计算所有质因子的乘积
	{
		int n = *it;
		mul(n);
	}
	printf("%s" , ch);
	return 0;
}

  1. 十进制是人类最常用的进制之一,且容易分析(至少本人这么觉得)。 ↩︎

  2. 对于 a b \frac{a}{b} ba来说,可以将其表示为 a × 1 b a \times \frac{1}{b} a×b1所以只要 1 b \frac{1}{b} b1能用有限位小数表示,那么 a b \frac{a}{b} ba就能用有限位小数表示。 ↩︎

  3. p p p必定可以表示为 p r pr pr的质数倍,且该质数是 p r pr pr的质因子所以 p r pr pr进制下可以用有限的非小数表示出 p p p,进而表示出该分数。 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值