Comet OJ - Contest #0 A 解方程(积性函数)(level 2)

题目链接

题意:

你只需要给出解的数量和所有解的 xyz 之和对 (109+7) 取模的值即可

若方程有无穷多组自然数解,则在这一行输出 “infty”(不含引号),否则在这一行输出两个整数,其中第一个整数表示方程的解数,第二个整数表示所有解的 xyz之和对 (109+7)取模的值,这两个整数之间用恰好一个空格隔开,行末不要有多余的空格。

解析:

\sqrt{n}是有理数的时候,只需要输出infty,因为只要保持y==z,就永远有解

那么其实答案最后可以化简成

n%4!=0   答案为 0 0

n%4==0 

答案为 n/4的因子数/2   n/4的因子和*(n/4)

然后你可以对于每一个n暴力枚举因子,只要你写的常数够小,那么就可以过,我比赛的时候也是这么过的。

但是这道题是有一个更优的解法的,只需要153ms

就是质因数分解。

令m=n/4 ,m最大达到5e8,但是我们并不需要枚举那么多质数,只需要枚举\sqrt{m}以内的质数。

因为如果m里面最多只存在一个大于\sqrt{m}的质因子,因为如果存在两个,那么乘积就大于m了。

那么对于这一个大于\sqrt{m}质因子,当我们把m对\sqrt{m}以内的质因子都分解了之后,

剩下了要么是1,要么就是那个大于\sqrt{m}的质因子。然后再进行判断处理就可以了。

要用质因数分解的原因是m的正因子和是一个积性函数

即,若a和b互质,那么f(ab)=f(a)f(b)  

那么这样我们在质因数分解的时候,不同质因子之间,因子和直接相乘就可以了。

而同一个因子,只要求和就可以了(f(8)=f(2^3)=1+2+4+8)

最后不要忘了,如果剩下的是一个质数(>1),还要对他进行求一次答案。

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

const int N = 1E5+10;
typedef long long ll;
const int MOD = 1e9+7;
int prime[N];

int main()
{
	int t;
	scanf("%d",&t);
	int w=5e8;
	int o;
	int cnt=0;
	for(int i=2;i*i<=w;i++){
		int en=sqrt(i);
		o=1;
		for(int j=2;j<=en;j++)
			if(i%j==0) {o=0;break;}
		if(o) prime[cnt++]=i;
	}
	while(t--){
		int n;
		scanf("%d",&n);
		int en=sqrt(n);
		o=0;
		for(int i=en-10;i<=en+10;i++)
			if(i*i==n) {o=1;break;}
		if(o)
		{
			printf("infty\n");
			continue;
		}
		if(n%4) 
		{
			printf("0 0\n");
			continue;
		}
		n=n/4;
		int x=1;
		ll ans=n;
		for(int i=0;i<cnt&&n>1;i++)
		{
			if(n%prime[i]==0){
				int y=1;
				o=1;
				int j=1;
				while(n%prime[i]==0)
				{
					j*=prime[i];
					n/=prime[i];
					o+=j;
					//tm%=MOD;
					y++;
				}
				x*=y;
				ans*=o;
				ans%=MOD;
			}
		}
		if(n>1) //n是一个质数
		{
			ans*=(n+1);
			x*=2;
		}
		ans%=MOD;
		printf("%d %lld\n",x/2,ans);

	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值