P6156 题解

莫比乌斯反演。推柿子。

\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^k f(\gcd(i,j)) \gcd(i,j) \]

\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^k\sum\limits_{d=1}^n\left[\gcd(i,j)=d\right]f(d) d \]

\[\sum\limits_{d=1}^n f(d)d\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left[\gcd(i,j)=1\right](id+jd)^k \]

\[\sum\limits_{d=1}^n f(d)d^{k+1}\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left[\gcd(i,j)=1\right](i+j)^k \]

\[\sum\limits_{d=1}^n f(d)d^{k+1}\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{l=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\left[l|d\right]\mu(l)(i+j)^k \]

\[\sum\limits_{d=1}^n f(d)d^{k+1}\sum\limits_{l=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\mu(l)\sum\limits_{i=1}^{\left\lfloor\frac{n}{dl}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{n}{dl}\right\rfloor}(il+jl)^k \]

\[\sum\limits_{d=1}^n f(d)d^{k+1}\sum\limits_{l=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\mu(l)l^k\sum\limits_{i=1}^{\left\lfloor\frac{n}{dl}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{n}{dl}\right\rfloor}(i+j)^k \]

前面的部分可以分块 \(O(n \sqrt n)\) 处理,关键是怎么预处理后面的部分。不难发现:

\[\sum\limits_{i=1}^{m}\sum\limits_{j=1}^{m}(i+j)^k=\sum\limits_{i=1}^{m}(i+1)^k+(i+2)^k+\dots+(i+n)^k=1(1+1)^k+2(1+2)^k+\cdots+(n-1)n^k+n(n+1)^k+(n-1)(n+2)^k+\dots+2(2n-1)^k+1(2n)^k \]

这个东西可以通过线性筛筛 \(1\)\(2n\) 每个数的 \(k\) 次幂,求两次前缀和得出。

\(Code\)

#include <iostream>
#include <cstdio>
using namespace std;
#define mod 998244353

int n,p[5000002],mu[5000002];
long long k,pow[10000002],sum[10000002],res[5000002];
bool vis[10000002];

long long power(long long x,long long y) {
	long long tot=1;
	while(y) {
		if(y%2) tot=(tot*x)%mod;
		x=(x*x)%mod,y/=2;
	}
	return tot;
}

void getmu() {
	vis[1]=pow[1]=mu[1]=sum[1]=1;
	for(int i=2;i<=10000000;i++) {
		if(!vis[i]) {
			p[++p[0]]=i,pow[i]=power(i,k);
			if(i<=5000000) mu[i]=-1;
		}
		for(int j=1;i*p[j]<=10000000;j++) {
			vis[i*p[j]]=1;
			pow[i*p[j]]=(pow[i]*pow[p[j]])%mod;
			if(i%p[j]==0) break;
			if(i*p[j]<=5000000) mu[i*p[j]]=-mu[i];
		}
		sum[i]=(sum[i-1]+pow[i])%mod;
	}
	for(int i=1;i<=10000000;i++) {
		if(i<=5000000) res[i]=(res[i-1]+pow[i]*mu[i])%mod;
		sum[i]=(sum[i-1]+sum[i])%mod;
	}
}

int main() {
	scanf("%d%lld",&n,&k);
	getmu();
	long long ans=0;
	for(int i=1;i<=n;i++) {
		int l=1,r=1;
		long long tot=0;
		while(l<=n/i) {
			r=(n/i)/((n/i)/l);
			tot=(tot+(res[r]-res[l-1])%mod*(sum[2*(n/i/l)]-2*sum[n/i/l])%mod)%mod;
			l=r+1;
		}
		ans=(ans+((i*pow[i])%mod*mu[i]*mu[i]*tot)%mod)%mod;
	}
	printf("%lld\n",(ans%mod+mod)%mod);
	return 0;
}

(我一开始没看 \(k\) 的数据范围用了 \(int\) 然后一直wa,还以为柿子推错了/kk)

posted @ 2022-07-31 16:06  Sharing666  阅读(43)  评论(0)    收藏  举报