牛客P21578 思维,数论

本文探讨了给定整数n下,寻找满足ab=c^d的所有不同四元组(a,b,c,d)的方法。通过数学分析,将问题转化为寻找特定结构的数,并使用高效算法进行枚举。

题意:

给定nnn,求有多少四元组(a,b,c,d)(a,b,c,d)(a,b,c,d)满足ab=cda^b=c^dab=cd

Solution:

从唯一分解看,幂b,db,db,d只改变质因数的幂,而不改变质因数的种数,因此,要满足题意,a,ca,ca,c一定存在结构一样的部分,设为xxx,那么
a=xk1c=xk2 a=x^{k_{1}}\\ c=x^{k_{2}} a=xk1c=xk2

  • x=1x=1x=1b,db,db,d不一定一样,且都任意取值,方案数为n2n^2n2,此时为a=c=1a=c=1a=c=1

  • a=c≠1a=c\neq1a=c=1时,a=c∈[2,n]a=c\in[2,n]a=c[2,n]b=d∈[1,n]b=d\in[1,n]b=d[1,n],方案数为n(n−1)n(n-1)n(n1)

  • 下面只需要考虑a≠ca\neq ca=c的情况

    当我们知道同样部分xxx的时候,我们很容易可以知道以这个数为最小结构的数有多少,而我们只需要枚举一个最小的xxx,就可以统计所有以xxx为最小结构的数,他们分别是
    x,x2,x3,.... x,x^2,x^3,.... x,x2,x3,....
    此时只需要找出序列长度大于222xxx,即x2≤n⇒x≤nx^2\leq n\Rightarrow x\leq\sqrt{n}x2nxn,我们用O(n)O(\sqrt{n})O(n)枚举xxx,只需要找出最大的iii满足xi≤nx^i\leq nxin,即可找出这些数,那么a,ca,ca,c一定出现在这些数之中,原题要满足
    xbk1=xdk2⇒bk1=dk2 x^{bk_{1}}=x^{dk_{2}}\Rightarrow bk_{1}=dk_{2} xbk1=xdk2bk1=dk2

    由于n≤109n\leq 10^9n109,因为232>1092^{32}>10^9232>109,于是i≤32i\leq 32i32,所以考虑枚举k1,k2k_{1},k_{2}k1,k2,由于a≠ca\neq ca=c,即k1≠k2k_{1}\neq k_{2}k1=k2,此时方程解的组数就是方案数,先化简方程至gcd(k1,k2)=1gcd(k_{1},k_{2})=1gcd(k1,k2)=1,即解
    bd=k2k1 \frac{b}{d}=\frac{k_{2}}{k_{1}} db=k1k2
    b=k2x≤n,d=k1x≤nb=k_{2}x\leq n,d=k_{1}x \leq nb=k2xn,d=k1xn,有x≤min{nk1,nk2}x\leq min\{\frac{n}{k_{1}},\frac{n}{k_{2}}\}xmin{k1n,k2n}

    如果不化简,这个xxx可能不是最大的

    最后,这个序列的元素的都用最小的xxx统计了,所以xxx的其他幂需要跳过,数组记录即可

// #include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<bitset>
#include<map>
using namespace std;

using ll=long long;
const int N=1e5+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=1e9+7;

ll n,ans;
bool vis[N];

int main()
{
    cin>>n; ans=(1ll*n*n%mod+1ll*n*(n-1)%mod)%mod;
    int limit=sqrt(n);
    for(int i=2;i<=limit;i++)
    {
        if(vis[i]) continue;
        ll max1=1,now=i;
        while(now*i<=n) max1++,now*=i;
        now=i;
        for(int j=1;j<=max1;j++)
        {
            if(now<=limit) vis[now]=true;
            for(int k=1;k<=max1;k++)
                if(j!=k) ans=(ans+n/max(j/__gcd(j,k),k/__gcd(j,k)))%mod;
            now*=i;
        }
    }
    cout<<ans;
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值