xtuoj 不定方程的正整数解

题目

思路

以上解决了如何将题目转换为代码问题。接下来就是如何编写代码了。

思路一(暴力)

首先我们需要分解a的质因数,利用试除法分解即可,然后过程中统计每个互不相同的质因数的个数k1,k2,...,kr,然后a的质因子个数就是(k1+1)*(k2+1)*...*(kr+1),接着就就调用这个函数,传入a^2,然后再-1除以2,得到结果。

还有一点就是数组的大小设置,这里的primes数组我是用来存a以内所有的素数的,但是其实没有必要全存下来,由于后续我们要采用分解质因数 ,所以这里我们的素数存到sqrt(a) 即可,然后可以用**n/ln(n)**来算大致个数。

思路二(朴素埃式筛)

这个就是优化了下分解质因数的方法,原来是试除法找质因子,现在直接先用埃式筛先找出所有的素数,然后用这些质数去试除,看看是不是因子。

朴素埃式筛主要是利用质数 i 的倍数(除了本身)必然是合数,从而筛去合数,留下素数。筛掉素数的2倍,3倍,...,直到该倍数超过N。

思路二(埃式筛优化)

然后埃式筛的一个常见优化就是不是从最小倍数 2i 开始筛,而是从i * i 开始筛起,**对于任意 k < i(k 是正整数),k×i 一定已经被比 i 小的质数标记过了。**比如 i 是5,我们要标记5的所有倍数,10、15、20、25、30...,但其实10=2*5,已经被2标记过了,15=3*5,已经被3标记过了,20=2*2*5,也被2标记过了,而25=5*5,这是第一次标记。这样可以减少一些重复标记的情况,也会减少循环次数。

思路三(线性筛)

这里利用的是每个合数被其最小的质因数筛去,任意一个合数,都能拆成 "最小质因子 × 一个比它大的数", primes[j] 就是这个 "最小质因子",i 就是那个 "比它大的数"------ 我们只要让 i 遍历所有数,primes[j] 遍历所有素数,就能凑出所有合数。

i%primes[j] == 0 时,说明 primes[j] 是 i 的最小质因子, 再用 break 保证每个合数只被自己的 "最小质因子" 造一次 ------ 这样就不会重复,效率才是线性的!

思路四(数学优化)

首先我们需要分解a的质因数,利用试除法分解 即可,然后过程中统计每个互不相同的质因数的个数k1,k2,...,kr,然后由a^2的质因数分解表达式知,a^2的质因数个数为t=(2k1+1)*(2k2+1)*...*(2kr+1),这个t怎么算呢,只需初始化t为1(因为要算乘积),然后t*=2*k+1,其中k是每次统计出的质因数个数,我们最终要求的ans就是(t-1)/ 2。

代码一

cpp 复制代码
#include <stdio.h>
#include <math.h>

// 计算 n 的因数总数
int countDivisors(long long n) {
	int count = 0;
	for (long long i = 1; i * i <= n; i++) {
		if (n % i == 0) {
			if (i * i == n) {
				count++;
			} else {
				count += 2;
			}
		}
	}
	return count;
}

int main() {
	int T;
	scanf("%d", &T);
	
	while (T--) {
		long long a;
		scanf("%lld", &a);
		
		long long divisor_total = countDivisors(a * a);
		long long result = (divisor_total - 1) / 2;  // 核心修改行
		printf("%lld\n", result);
	}
	
	return 0;
}

代码二

cpp 复制代码
#include<stdio.h>
#define N 10007
typedef enum { false, true } bool;

int T,a;
int cnt=0,primes[N+1];
bool st[N+1]={false};	//st[x]表示x是否被筛掉

void generate_primes(){
	//埃式筛
	for(int i=2;i<=N;i++){
		if(st[i]) continue;
		primes[cnt++]=i;
		for(int j=i+i;j<=N;j+=i){
			st[j]=true;
		}
	}
}

void solves(int a){
	int sa2=1;
	int ans=0;
	for(int i=0;primes[i]<=a/primes[i]&&i<cnt;i++){
		int sa=0;
		while(a%primes[i]==0){
			a/=primes[i];
			sa++;
		}
		sa2*=2*sa+1;
	}
	if(a>1) sa2*=3;
	ans=(sa2-1)/2;
	printf("%d\n",ans);
}

int main(){
	generate_primes();
	scanf("%d",&T);
	while(T--){
		scanf("%d",&a);
		solves(a);
	}
	return 0;
}

代码二(优化)

cpp 复制代码
#include<stdio.h>
#define N 10007
typedef enum { false, true } bool;

int T,a;
int cnt=0,primes[N+1];
bool st[N+1]={false};	//st[x]表示x是否被筛掉

void generate_primes(){
	//埃式筛
	for(int i=2;i<=N;i++){
		if(st[i]) continue;
		primes[cnt++]=i;
		for(int j=i*i;j<=N;j+=i){
			st[j]=true;
		}
	}
}

void solves(int a){
	int sa2=1;
	int ans=0;
	for(int i=0;primes[i]<=a/primes[i]&&i<cnt;i++){
		int sa=0;
		while(a%primes[i]==0){
			a/=primes[i];
			sa++;
		}
		sa2*=2*sa+1;
	}
	if(a>1) sa2*=3;
	ans=(sa2-1)/2;
	printf("%d\n",ans);
}

int main(){
	generate_primes();
	scanf("%d",&T);
	while(T--){
		scanf("%d",&a);
		solves(a);
	}
	return 0;
}

代码三

cpp 复制代码
#include<stdio.h>
#define N 10007
typedef enum { false, true } bool;

int T,a;
int cnt=0,primes[N+1];
bool st[N+1]={false};	//st[x]表示x是否被筛掉

void generate_primes(){
	//线性筛
	for (int i = 2; i <= N; i ++ )
	{
		if (!st[i]) primes[cnt ++ ] = i;
		for (int j = 0; primes[j] <= N / i; j ++ )
		{
			st[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

void solves(int a){
	int sa2=1;
	int ans=0;
	for(int i=0;primes[i]<=a/primes[i]&&i<cnt;i++){
		int sa=0;
		while(a%primes[i]==0){
			a/=primes[i];
			sa++;
		}
		sa2*=2*sa+1;
	}
	if(a>1) sa2*=3;
	ans=(sa2-1)/2;
	printf("%d\n",ans);
}

int main(){
	generate_primes();
	scanf("%d",&T);
	while(T--){
		scanf("%d",&a);
		solves(a);
	}
	return 0;
}

代码四(最推荐,而且非常快,代码短)

cpp 复制代码
#include<stdio.h>

int T,a;

void solves(int a){
	int s=1;
	for(int i=2;i*i<=a;i++){
		int sa=0;
		while(a%i==0){
			sa++;
			a/=i;
		}
		s*=2*sa+1;
	}
	if(a>1) s*=3;
	int ans=(s-1)/2;
	printf("%d\n",ans);
}

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&a);
		solves(a);
	}
	return 0;
}

代码积累

试除法

cpp 复制代码
bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}

埃式筛

cpp 复制代码
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}

线性筛

cpp 复制代码
int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

试除法分解质因数

cpp 复制代码
void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}
相关推荐
dog2502 小时前
让算法去学习,而不是去启发
学习·算法
草莓熊Lotso2 小时前
《算法闯关指南:动态规划算法--斐波拉契数列模型》--04.解码方法
c++·人工智能·算法·动态规划
alphaTao2 小时前
LeetCode 每日一题 2025/12/1-2025/12/7
数据库·算法·leetcode
苏小瀚2 小时前
[算法]---分治-快排和归并
java·算法·leetcode
Jac_kie_層樓2 小时前
力扣hot100刷题记录(12.1)
算法·leetcode·职场和发展
无限进步_2 小时前
寻找数组中缺失数字:多种算法详解与比较
c语言·开发语言·数据结构·算法·排序算法·visual studio
多恩Stone2 小时前
【3DV 进阶-9】Hunyuan3D2.1 中的 MoE
人工智能·pytorch·python·算法·aigc
xu_yule2 小时前
数据结构(4)链表概念+单链表实现
数据结构·算法·链表
代码栈上的思考3 小时前
二叉树的层序遍历:4道例题讲解
算法·宽度优先·队列在宽度优先搜索中的应用