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

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

```cpp #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)