别人都A了就我部分分系列
经过一通乱试发现可以转化为求满足\(i+j=n\)且\(i,j\)互质的数对\((i,j)\),则\(ans+=\frac{n}{(i+j)^2}\)
这里有个奇奇怪怪的性质,考场上除了打表之外应该还真没有推出来的可能
- 对于一个\(n\), 满足\(i+j=n\)且\(i,j\)互质的数对\((i,j)\)有\(\varphi(n)\)对
所以每个\(k\in[1,\sqrt n]\)的贡献就是\(\varphi (k)\)对正解就是这么无理取闹
想出来是不太可能了,证明一下吧
首先满足\(i+j=n\)的数对\((i,j)\)有\(n-1\)对,每个\(i \in [1, n-1]\)都对应着一对
这里有个\(\varphi(n)\),那大概每个与\(n\)互质的\(i\)都对应着一对
尝试证明如下性质:
- 如果\(i\)与\(n\)互质,则有\((n-i)\)与\(n,i\)均互质
挺好证的,可以反证,假设它们有公因子即可
那由这个性质就可以求出数对数了
- 线性筛求欧拉函数
依据如下性质即可
如果\(n\)为素数,\(\varphi (n) = n-1\)
如果\(a, b\)互质,\(\varphi (ab) = \varphi(a)*\varphi(b)\)
如果\(n\)为某个素数\(p\)的幂次(即 \(n = p^a\)),此时p与p不互质,\(\varphi (n) = (p-1)*p^{a-1}\)
至于定理3,其实并不用特殊处理
代码:
for (int i=2; i<=lim; ++i) {
if (!npri[i]) pri[++pcnt]=i, phi[i]=i-1;
for (int j=1; j<=pcnt&&i*pri[j]<=lim; ++j) {
npri[i*pri[j]]=1;
if (!(i%pri[j])) {phi[i*pri[j]]=pri[j]*phi[i]; break;}
else phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000010
#define ll long long
#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll n;
namespace force{
ll ans;
void solve() {
for (int i=1; i<n; ++i)
for (int j=1; i+j<=n; ++j)
if (!(i*j%(i+j))) {
//cout<<i<<' '<<j<<endl;
++ans;
}
printf("%lld\n", ans);
exit(0);
}
}
namespace task1{
ll ans;
void solve() {
for (int i=1; i<n; ++i)
for (int j=1; i+j<=n; ++j) {
if (i*(i+j) + j*(i+j)>n) continue;
//cout<<i*(i+j)<<' '<<j*(i+j)<<endl;
++ans;
}
cout<<ans<<endl;
}
}
namespace task2{
ll ans;
ll gcd(ll a, ll b) {return !b?a:gcd(b, a%b);}
ll cnt[N];
void solve() {
bool flag;
for (int i=1,t; i<n; ++i) {
flag=1;
for (int j=1; i+j<=n; ++j) {
if ((i==(i>>1)<<1&&j==(j>>1)<<1) || gcd(i, j)!=1) continue;
t = n/((i+j)*(i+j));
if (t) {flag=0; ans+=t; ++cnt[i+j];}
else break;
}
if (flag) break;
}
printf("%lld\n", ans);
for (int i=1; i<=50; ++i) cout<<cnt[i]<<' '; cout<<endl;
vector<int> v;
v.end();
exit(0);
}
}
namespace task{
ll ans;
ll pri[N], phi[N], pcnt;
bool npri[N];
void solve() {
int lim=sqrt(n);
npri[0]=npri[1]=1;
for (int i=2; i<=lim; ++i) {
if (!npri[i]) pri[++pcnt]=i, phi[i]=i-1;
for (int j=1; j<=pcnt&&i*pri[j]<=lim; ++j) {
npri[i*pri[j]]=1;
if (!(i%pri[j])) {phi[i*pri[j]]=pri[j]*phi[i]; break;}
else phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
//for (int i=1; i<=lim; ++i) cout<<phi[i]<<' '; cout<<endl;
for (int i=1; i<=lim; ++i) ans+=phi[i]*(n/(i*i));
printf("%lld\n", ans);
exit(0);
}
}
signed main()
{
n=read();
//task2::solve();
task::solve();
return 0;
}