这题比较难,于是就来写下题解吧

公式警告

题目意思非常简明,就是让你求成立的四元组的个数,考虑如何解决

一开始,我的想法是两边同时取对化简,但是搞了很久,发现复杂度至少要n^2才可做,于是放弃了这个做法。

我们现在来考虑下其他方法。。。

首先,我们将a和c分解质因数

那么一定有:




又因为,那么分别有:

即:

意思是,a和c分解质因数后,对应的质因数的指数一定是成比例的!

那么,我们不妨设有最简分数,那么一定有:

对于任意对于任意
且,

那么,我们设


由上述关系,我们还可以得到

那么,原式就可以化为:
我们把i叫做"公共基底数"

那么,我们可以考虑枚举这个"i",因为<=n,所以我们枚举的的个数其实是很少的,可以直接计算。

假如,我们有,那么,我们将这些数两两组合(即枚举对应的a和c)

假如,我们将组合了,那么,我们需要找到的多少次方相等

假设,,那么有:

于是有:

那么,我们第一想法就是求k和g的lcm,因为,所以一定是的倍数。

那么我们就用这个想法做,我们先设C=lcm(k,g),那么,只要是C的倍数的V,都是符合答案的,又

因为

所以有:
意思是,这要q的取值符合这个范围,那么取相应的V都是符合的,所以答案加上q即可

这个式子可能不太好看,我们化简下:
因为

故,

emmm,推了这么久式子,整个人都快累死了。。。

然后,试试样例。。。emmm,超时了???why???

冷静分析。。。。

我们发现,若i取1时,i的任意次方都=1,我们永远也算不到i大于n的那天!!

怎么办呢?很简单,我们把1作为底数的情况单独考虑,那么,情况数就是n*n(两指数都从n个数中随便选),然后我们i从2开始枚举就好了。。。

再来。。。wa了???

qwq,怎么回事?

原来,我们枚举i的时候,若我们现在的i可以用一个小于i的数j的k次方表示,即,那么,我们在枚举到j的时候,就已经把现在的情况算了一遍了,所以,我们再算的话就算多了!于是,我们把这种情况的i给剔除掉不算,就行了。。。

然后。。。终于过了qwq。。。

(其实可以先统计底数为1和指数为1的情况,然后i就可以只枚举到了,但个人感觉优化不大(毕竟后面就是O(1)了))

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
bool s[1000001];
int main(){
    int n;
    scanf("%d",&n);
    int ans=(1LL*n*n)%mod;//把1作为底的情况先算了
    for(int i=2;i<=n;++i){//枚举公共基底数i
        if(s[i]){
            continue;
        }
        int now=i,maxe=1;//枚举最高指数
        while(now<=n/i){
            ++maxe,now*=i;s[now]=1;
        }
        for(int j=1;j<=maxe;++j){//左边底数为(i^j)
            for(int k=1;k<=maxe;++k){//右边底数为(i^k)
                //求(i^j)^a==(i^k)^b(a,b<=n)的个数
                int C=__gcd(j,k),A=k/C,B=j/C;
                ans=(ans+min((n/A),(n/B)))%mod;//这里把乘化成除更好,不会爆int
            }
        }
    }
    printf("%d",ans);
    return 0;
}