题目

思路


以上解决了如何将题目转换为代码问题。接下来就是如何编写代码了。
思路一(暴力)
首先我们需要分解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;
}