CF1717E. Madoka and The Best University(数论)
CF1717E. Madoka and The Best University
数论真有意思啊哈!
解题思路
在 \(a,b,c\) 中最特殊的是 \(c\),因为 \(a,b\) 是对称轮换的。所以我们考虑枚举每个 \(c\)。范围为 \([1,n-2]\)。
为了方便表示,我们令 \(g=\gcd(a,b)\)。
我们观察 \(g\) 最基本的性质,也就是 \(g\) 能整除 \(a,b\),那么以为着 \(g\mid a+b\)。由于 \(a+b=n-c\),所以 \(g\) 能整除 \(n-c\)。我们令 \(n-c=k\cdot g\),\(k=\frac {n-c}g\)。由于 \(g\) 为 \(a,b\) 的最小公因数,\(\gcd(\frac a g,\frac b g)=1\)。由因为我们知道 \(\frac a g+\frac bg=k\),所以满足条件的 \(a,b\) 有 \(\varphi(k)\) 对。
那么就做完了。
值得注意的是,在实现时我们可以枚举 \(g\)。因为枚举 \(c\) 的时间复杂度是 \(O(n\sqrt n)\)。而枚举 \(g\) 只需要 \(O(n\log n)\)。
代码实现
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
char ch=getchar();
int f=1,x=0;
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
char read_char() {
char ch=getchar();
while(!isalpha(ch)) {
ch=getchar();
}
return ch;
}
const int MAXN=1e5+10,MOD=1e9+7;
int n,cnt;
int is[MAXN],p[MAXN],phi[MAXN];
int gcd(int a,int b) {
return !b? a:gcd(b,a%b);
}
int lcm(int a,int b) {
return a/gcd(a,b)*b;
}
void sieve(int n) {
phi[1]=1;
for(int i=2;i<=n;i++) {
if(!is[i]) {
p[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&p[j]*i<=n;j++) {
is[p[j]*i]=1;
if(i%p[j]==0) {
phi[p[j]*i]=phi[i]*p[j];
break;
}
phi[p[j]*i]=phi[i]*(p[j]-1);
}
}
}
signed main() {
sieve(MAXN-10);
cin>>n;
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=i*2;j<=n-1;j+=i) {
ans=(ans+lcm(i,n-j)%MOD*phi[j/i]%MOD)%MOD;
}
}
cout<<ans<<endl;
return 0;
}