[ACM]【LCM/唯一分解定理】牛客算法周周练5 求幂

求幂

传送门
题意:寻找有多少对 a a a b b b c c c d ∈ [ 1 , n ] d\in[1,n] d[1,n],满足 a b = c d a^b=c^d ab=cd
在这里插入图片描述

思路:

看似简单的题目往往都暗藏玄机。
本思路参考题解
主要操作:
第一步,用唯一分解定理将原式简化为 ( i j ) x = ( i k ) y (i^j)^x=(i^k)^y (ij)x=(ik)y
第二步,按照范围枚举 i i i j j j k k k
第三步,找到 i j i^j ij i k i^k ik最小公倍数,求得满足 ( i j ) x = ( i k ) y (i^j)^x=(i^k)^y (ij)x=(ik)y x x x y ∈ [ 1 , n ] y\in[1,n] y[1,n] x x x个数(ie. y y y的个数)。
具体原理:
很容易想到,一开始要将 A A A C C C用唯一分解定理表示。由于他们的某个幂相等,易得他们分解出来的质数是一一对应的。即 A = q 1 a 1 + q 2 a 2 + . . . + q p a p A=q_{1}^{a_1}+q_{2}^{a_2}+...+q_{p}^{a_p} A=q1a1+q2a2+...+qpap C = q 1 b 1 + q 2 b 2 + . . . + q p b p C=q_{1}^{b_1}+q_{2}^{b_2}+...+q_{p}^{b_p} C=q1b1+q2b2+...+qpbp。并且有 a i × B = b i × D , i ∈ [ 1 , p ] a_{i}\times B=b_i\times D,i\in[1,p] ai×B=bi×D,i[1,p]。我们设最简分数 m n = d b = a i b i \frac{m} n=\frac d b=\frac {a_i}{b_i} nm=bd=biai,设 i = q 1 a 1 m + q 2 a 2 m + . . . + q p a p m = q 1 b 1 n + q 2 b 2 n + . . . + q p b p n i=q_{1}^{\frac {a_1}{m}}+q_{2}^{\frac {a_2}{m}}+...+q_{p}^{\frac {a_p}{m}}=q_{1}^{\frac {b_1}{n}}+q_{2}^{\frac {b_2}{n}}+...+q_{p}^{\frac {b_p}{n}} i=q1ma1+q2ma2+...+qpmap=q1nb1+q2nb2+...+qpnbp称为 “公共基底数”,原式就等价于 ( i m ) b = ( i n ) d (i^m)^b=(i^n)^d (im)b=(in)d
为了直观,把 m m m换成 j j j n n n换成 k k k b b b换成 x x x d d d换成 y y y。根据条件,要求 i j i^j ij i k i^k ik小于等于 n n n x x x y y y小于等于 n n n
( i j ) x = ( i k ) y (i^j)^x=(i^k)^y (ij)x=(ik)y意味着 j × x = k × y j\times x=k\times y j×x=k×y,我们首先遍历 i i i j j j k k k,然后要找到满足这个关系的 x x x y y y的对数。很好找,只需要求 j j j k k k的最小公倍数,在最小公倍数的基础上乘正整数,直到 x x x y y y任意一个大于 n n n。设正整数为 q q q q q q的最大值就等于满足这个关系的 x x x y y y的对数。 q × l c m ( j , k ) = j × x = k × y ≤ j × n , k × n q\times lcm(j,k)=j\times x=k\times y\le{j\times n},{k\times n} q×lcm(j,k)=j×x=k×yj×n,k×n,于是, q ≤ m i n ( j × n l c m , k × n l c m ) q\le{min}(\frac{j\times n}{lcm},\frac{k\times n}{lcm}) qmin(lcmj×n,lcmk×n)
实现:
有三个地方需要注意:
(1) i = 1 i=1 i=1要特判,不然幂次运算陷入死循环。
(2)用vis数组判重,减少重复计算,寻找 i j i^j ij i k i^k ik的上限的时候,把经过的都标记一下就行了。
(3)如果直接用 j × n j\times n j×n来算,会爆,又因为\符号自带floor功能,不能先除lcm再乘。于是选择直接拿gcd, j × n l c m = g c d × j × n j × k = g c d × n k = n k g c d \frac{j\times n}{lcm}=\frac{gcd\times j\times n}{j\times k}=\frac{gcd\times n}{k}=\frac{n}{\frac{k}{gcd}} lcmj×n=j×kgcd×j×n=kgcd×n=gcdkn。众所周知, k g c d \frac{k}{gcd} gcdk为一整数。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
bool vis[1000004];
inline int read(){
	int k=0,j=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') j=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){k=(k<<1)+(k<<3)+ch-'0';ch=getchar();}
	return k*j;
}
ll gcd(ll a,ll b){
	if(b==0) return a;
	else return gcd(b,a%b);
}
int main(){
	ll n=(long long)read();
	ll ans=(n*n)%mod;//特判
	//开始遍历i
	for(ll i=2;i<=n;i++){
		if(vis[i]) continue;
		ll maxn=1;//不超过n的最大的幂次
		ll now=i;//幂次后的数
		while(now<=n/i){
			maxn++;
			now*=i;
			vis[now]=1;//确定可达,才标记
		}
		for(ll j=1;j<=maxn;j++){
			for(ll k=1;k<=maxn;k++){
				ll g=gcd(j,k);
				ll tmp=k/g,tmp2=j/g;
				ans=(ans+min(n/tmp,n/tmp2))%mod;
			}
		}
	}
	printf("%lld\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值