题解 求和

传送门

  • 形如 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n[\gcd(i, j)=1]\) 的式子别着急莫比乌斯反演,它等于 \((2\sum\limits_{i=1}^n\varphi(i))-1\)

于是式子被化为

\[\sum\limits_{i=1}^n(-1+2\sum\limits_{j=1}^{\lfloor\frac{n}{i}\rfloor}\varphi(j))\sum\limits_{d=1}^kf_d(i) \]

\(\varphi\) 相关那部分可以杜教筛做到 \(O(n^{\frac{2}{3}})\),关键在于后一部分
这个 \(f\) 的定义看起来比较可以容斥
\(\lambda(x)=f_{\infty}(x)=\prod\limits_i(-1)^{a_i}\)
尝试表示出 \(F_d(n)=\sum\limits_{i=1}^nf_d(i)\)
\(\Lambda(n)=\sum\limits_{i=1}^n\lambda(i)\)
容斥有哪些质因子出现超过 \(d\) 次可得

\[\begin{aligned} F_d(i)&=\sum\limits_{i=1}^n\mu(i)\sum\limits_{j=1}^{\lfloor\frac{n}{i^{d+1}}\rfloor}\lambda(i^{d+1}j)\\ &=\sum\limits_{i=1}^n\mu(i)\lambda^{d+1}(i)\Lambda(\lfloor\frac{n}{i^{d+1}}\rfloor)\\ &=\sum\limits_{i=1}^{n^{\frac{1}{d+1}}}\mu(i)\lambda^{d+1}(i)\Lambda(\lfloor\frac{n}{i^{d+1}}\rfloor)\\ \end{aligned}\]

发现只要 \(\Lambda\) 能快速求这个东西预处理一部分后后面暴力的复杂度是 \(O(n^{\frac{2}{3}})\)
那么就是求 \(\lambda\) 的前缀和了
这个东西看起来很类似 \(\mu\),那么同样卷上一个 \(I\) 看看能得到什么

\[\sum\limits_{d\mid n}\lambda(d)=[n\ 是完全平方数] \]

证明考虑这个东西实际上是在枚举质因子的幂次
当其它质因子指数确定时,当前质因子有 \(a_i+1\) 种选法
若存在一个质因子使 \(2\mid (a_i+1)\) 则两两配对后总贡献一定抵消成 0
否则 \(a_i\) 均为偶数,考虑 \((1, 2), (3, 4)\cdots\) 配对后仅在指数均为 0 时产生 1 贡献
那么现在 \(\Lambda\) 也可以杜教筛了
整体复杂度 \(O(n^{\frac{2}{3}})\)在 TLEcoders 上死活卡不过去

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#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 ll read() {
	ll 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;
int k;

namespace task1{
	char **f;
	bool *npri;
	unsigned *pri, *mu, *lowc, pcnt, ans;
	unsigned F(unsigned n) {
		unsigned ans=0;
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			ans+=(unsigned)(mu[r]-mu[l-1])*(n/l)*(n/l);
		}
		return ans;
	}
	void solve() {
		int lim=min(k, 23);
		npri=new bool[n+10];
		pri=new unsigned[n+10];
		mu=new unsigned[n+10];
		lowc=new unsigned[n+10];
		f=new char*[n+10];
		for (int i=1; i<=n; ++i) {
			f[i]=new char[lim+1];
			memset(f[i], 0, sizeof(char)*(lim+1));
		}
		memset(npri, 0, sizeof(bool)*(n+10));
		memset(pri, 0, sizeof(unsigned)*(n+10));
		memset(mu, 0, sizeof(unsigned)*(n+10));
		memset(lowc, 0, sizeof(unsigned)*(n+10));
		mu[1]=1;
		for (int i=1; i<=lim; ++i) f[1][i]=2;
		for (int i=2; i<=n; ++i) {
			if (!npri[i]) {
				pri[++pcnt]=i, lowc[i]=1, mu[i]=-1;
				for (int j=1; j<=lim; ++j) f[i][j]=3;
			}
			for (int j=1,x; j<=pcnt&&1ll*i*pri[j]<=n; ++j) {
				npri[x=i*pri[j]]=1;
				if (!(i%pri[j])) {
					lowc[x]=lowc[i]+1;
					for (int t=lim; t>=lowc[x]&&f[i][t]; --t)
						f[x][t]=f[i][t]^1;
					break;
				}
				else {
					mu[x]=-mu[i]; lowc[x]=1;
					for (int t=lim; t&&f[i][t]; --t)
						f[x][t]=f[i][t]^1;
				}
			}
		}
		for (int i=2; i<=n; ++i) mu[i]+=mu[i-1];
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			unsigned sum=0;
			for (int i=l; i<=r; ++i) {
				if (k>lim&&f[i][lim]) sum+=(k-lim)*(f[i][lim]==2?1:-1);
				for (int j=lim; j&&f[i][j]; --j) sum+=f[i][j]==2?1:-1;
			}
			ans+=F(n/l)*sum;
		}
		printf("%u\n", ans%(1<<30));
	}
}

namespace task2{
	#define N 100000010
	bool *npri;
	unsigned *pri, *mu, pcnt, ans;
	unsigned F(unsigned n) {
		unsigned ans=0;
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			ans+=(unsigned)(mu[r]-mu[l-1])*(n/l)*(n/l);
		}
		return ans;
	}
	void solve() {
		// cout<<double(sizeof(pri)*3)/1000/1000<<endl;
		npri=new bool[N];
		pri=new unsigned[N/2];
		mu=new unsigned[N];
		memset(npri, 0, sizeof(bool)*N);
		mu[1]=1;
		for (int i=2; i<=n; ++i) {
			if (!npri[i]) pri[++pcnt]=i, mu[i]=-1;
			for (int j=1,x; j<=pcnt&&1ll*i*pri[j]<=n; ++j) {
				npri[x=i*pri[j]]=1;
				if (!(i%pri[j])) break;
				else mu[x]=-mu[i];
			}
		}
		for (int i=2; i<=n; ++i) mu[i]+=mu[i-1];
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			ans+=F(n/l)*(mu[r]-mu[l-1]);
		}
		printf("%u\n", ans%(1<<30));
	}
}

namespace task{
	#undef N 
	#define N 5000010
	ll pw[42][100010];
	bool npri[N];
	int pri[N], pcnt;
	// unordered_map<ll, unsigned> mp1, mp2;
	unsigned mp1[100010], mp2[100010];
	unsigned phi[N], lambda[N], slamb[N], mu[N], ans;
	inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
	unsigned qphi(ll n) {
		if (n<N) return phi[n];
		if (mp1[::n/n]) return mp1[::n/n];
		// if (mp1.find(n)!=mp1.end()) return mp1[n];
		unsigned ans=(n&1)?((n+1)/2)*n:(n/2)*(n+1);
		for (ll l=2,r; l<=n; l=r+1) {
			r=n/(n/l);
			ans-=(unsigned)(r-l+1)*qphi(n/l);
		}
		return mp1[::n/n]=ans;
	}
	unsigned Lambda(ll n) {
		if (n<N) return slamb[n];
		// if (mp2.find(n)!=mp2.end()) return mp2[n];
		if (mp2[::n/n]) return mp2[::n/n];
		unsigned ans=sqrt(n);
		for (ll l=2,r; l<=n; l=r+1) {
			r=n/(n/l);
			ans-=(r-l+1)*Lambda(n/l);
		}
		return mp2[::n/n]=ans;
	}
	unsigned F(int d, ll n) {
		// cout<<"d: "<<d<<' '<<n<<endl;
		unsigned ans=0;
		int lim=ceil(pow(n, 1.0/(d+1)));
		// cout<<"lim: "<<lim<<' '<<d+1<<endl;
		for (int i=1; i<=lim; ++i) if (pw[d+1][i])
			ans+=mu[i]*((d+1)&1?lambda[i]:1)*Lambda(n/pw[d+1][i]);
		return ans;
	}
	void solve() {
		phi[1]=lambda[1]=mu[1]=1;
		for (int i=2; i<N; ++i) {
			if (!npri[i]) pri[++pcnt]=i, phi[i]=i-1, mu[i]=lambda[i]=-1;
			for (int j=1,x; j<=pcnt&&i*pri[j]<N; ++j) {
				npri[x=i*pri[j]]=1;
				lambda[x]=-lambda[i];
				if (!(i%pri[j])) {phi[x]=phi[i]*pri[j]; break;}
				else phi[x]=phi[i]*(pri[j]-1), mu[x]=-mu[i];
			}
		}
		for (int i=1; i<N; ++i) phi[i]+=phi[i-1], slamb[i]=slamb[i-1]+lambda[i];
		for (int i=1; i<100010; ++i) pw[1][i]=i;
		for (int d=2; d<=min(k+1, 34); ++d) {
			int lim=ceil(pow(n, 1.0/d));
			for (int i=1; i<=lim; ++i) pw[d][i]=pw[d-1][i]*i;
		}
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			unsigned tem=2*qphi(n/l)-1;
			for (int i=1; i<=min(k, 33); ++i) ans+=(F(i, r)-F(i, l-1))*tem;
			if (k>33) ans+=(k-33)*(F(33, r)-F(33, l-1))*(2*qphi(n/l)-1);
		}
		printf("%u\n", ans%(1<<30));
	}
}

signed main()
{
	freopen("sum.in", "r", stdin);
	freopen("sum.out", "w", stdout);

	n=read(); k=read();
	// force::solve();
	// if (n<=10000000) task1::solve();
	// else task2::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-19 20:50  Administrator-09  阅读(7)  评论(0编辑  收藏  举报