题解 神炎皇

传送门

别人都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)\)
    如果 \(i\) 与 质数\(r\) 不互质,有 \(\varphi(i*r) = \varphi(i)*r\),证明见这里

代码:

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;
}
posted @ 2021-07-28 19:26  Administrator-09  阅读(12)  评论(0编辑  收藏  举报