题解 DZY Loves Math IV/P4240 毒瘤之神的考验/暴力题

DZY Loves Math IV
P4240 毒瘤之神的考验
暴力题

不知道之前 DZY 这题我为什么没写题解大概是忘了,所以先来补一下
因为 \(m\leqslant 1e9\),所以推法和后面并不太一样
\(p=\prod p_i^{c_i-1},q=\prod p_i\)

\[\begin{aligned} S(n, m)&=p\sum\limits_{i=1}^m\varphi(iq)\\ &=p\sum\limits_{i=1}^m\varphi(\frac{q}{\gcd(i, q)}\times i\times\gcd(i, q))\\ &=p\sum\limits_{i=1}^m\varphi(\frac{q}{\gcd(i, q)})\times \varphi(i\times\gcd(i, q))\\ &=p\sum\limits_{i=1}^m\varphi(\frac{q}{\gcd(i, q)})\times \varphi(i)\times\gcd(i, q)\\ &=p\sum\limits_{i=1}^m\varphi(\frac{q}{\gcd(i, q)})\times \varphi(i)\times\sum\limits_{d\mid\gcd(i, q)}\varphi(d)\\ &=p\sum\limits_{i=1}^m\varphi(i)\times\sum\limits_{d\mid\gcd(i, q)}\varphi(\frac{q}{d})\\ &=p\sum\limits_{d\mid q}\varphi(\frac{q}{d})\sum\limits_{i=1}^{\lfloor\frac{m}{d}\rfloor}\varphi(id)\\ &=p\sum\limits_{d\mid q}\varphi(\frac{q}{d})S(d, \lfloor\frac{m}{d}\rfloor)\\ \end{aligned}\]

边界为 \(n=1\) 时杜教筛,复杂度证明见这里

然后是 P4240 毒瘤之神的考验
发现现在 \(n, m\leqslant 1e5\),但有 \(1e4\) 组多测
式子太长了不想手打一遍了
image
image
\(f(x)=\sum\limits_{d\mid x}\frac{d}{\varphi(d)}\mu(\frac{x}{d})\)
\(g(y, x)=\sum\limits_{i=1}^x\varphi(iy)\),有 \(g(y, x)=g(y, x-1)+\varphi(xy)\)
\(h(x, y, z)=\sum\limits_{i=1}^zf(i)g(i, x)g(i, y)\),有 \(h(x, y, z)=h(x, y, z-1)+f(z)g(z, x)g(z, y)\)
这里 \(f\)\(g\) 可以 \(O(n\ln n)\) 预处理出来
然后考虑根号分治
\(h\) 可以 \(O(nB^2)\) 预处理出 \(\frac{m}{T}\leqslant B\) 的部分
剩下的部分有 \(T\leqslant\frac{m}{B}\),暴力算即可
image

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#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;
}

int n, m;
bool npri[N];
ll f[N], invphi[N];
vector<ll> g[N];
vector<ll> h[55][55];
const int len=50;
int pri[N], mu[N], phi[N], pcnt;
const ll mod=998244353;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

void init() {
	mu[1]=phi[1]=1;
	for (int i=2; i<N; ++i) {
		if (!npri[i]) pri[++pcnt]=i, phi[i]=i-1, mu[i]=-1;
		for (int j=1,x; j<=pcnt&&i*pri[j]<N; ++j) {
			npri[x=i*pri[j]]=1;
			if (!(i%pri[j])) {phi[x]=phi[i]*pri[j]; break;}
			else phi[x]=phi[i]*phi[pri[j]], mu[x]=-mu[i];
		}
	}
	for (int i=1; i<N; ++i) invphi[i]=qpow(phi[i], mod-2);
	for (int i=1; i<N; ++i)
		for (int j=i; j<N; j+=i)
			f[j]=(f[j]+i*invphi[i]*mu[j/i])%mod;
	for (int i=1; i<N; ++i) {
		g[i].resize(N/i+1);
		for (int j=1,lim=N/i; j<=lim; ++j)
			g[i][j]=(g[i][j-1]+phi[i*j])%mod;
	}
	for (int i=1; i<=len; ++i)
		for (int j=1; j<=len; ++j) {
			h[i][j].resize((N-1)/max(i, j)+1);
			for (int k=1,lim=(N-1)/max(i, j); k<=lim; ++k)
				h[i][j][k]=(h[i][j][k-1]+f[k]*g[k][i]%mod*g[k][j])%mod;
		}
}

ll solve(int n, int m) {
	if (n>m) swap(n, m);
	ll ans=0;
	// for (int t=1; t<=n; ++t) ans=(ans+f[t]*g[t][n/t]%mod*g[t][m/t])%mod;
	int lim=m/len;
	for (int t=1; t<=lim; ++t) ans=(ans+f[t]*g[t][n/t]%mod*g[t][m/t])%mod;
	for (int l=lim+1,r; l<=n; l=r+1) {
		r=min(n/(n/l), m/(m/l));
		ans=(ans+h[n/l][m/l][r]-h[n/l][m/l][l-1])%mod;
	}
	return (ans%mod+mod)%mod;
}

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

	int T=read();
	init();
	while (T--) {
		n=read(); m=read();
		printf("%lld\n", solve(n, m));
	}
	
	return 0;
}
posted @ 2022-03-01 21:51  Administrator-09  阅读(1)  评论(0编辑  收藏  举报