BSOJ5019&P6156&P6222 简单题
题目
求:
\[\large \sum_{i=1}^n\sum_{j=1}^m(i+j)^k\mu^2(\gcd(i,j))\gcd(i,j)
\]
\(\large T = 10^4,1 \leq K < 2^{31},n,m\le 10^7\)
题目:
BSOJ5019【Digimon】3 primary color(三原色)
分析
先推一下柿子:
\[\large
\begin{split}
&\ \ \ \ \ \sum_{i=1}^n\sum_{j=1}^m(i+j)^k\mu^2(\gcd(i,j))\gcd(i,j)\\
&=\sum_{d=1}^nd^{k+1}\mu^2(d)\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac md\rfloor}(i+j)^k[(i,j)=1]\\
&=\sum_{d=1}^{n}\mu^2(d)d^{k+1}\sum_{t=1}^{\lfloor\frac nd\rfloor}\mu(t)t^k\sum_{i=1}^{\lfloor\frac n{td}\rfloor}\sum_{j=1}^{\lfloor\frac m{td}\rfloor} (i+j)^k
\end{split}
\]
然后设 \(\large S(n,m)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m(i+j)^k\)
发现剩下的柿子还是一个二次除法分块,于是考虑传统艺能,直接枚举倍数把第二个除法分块变成卷积的形式:
设 \(T=td\):
\[\large \sum_{T=1}^{n}T^kS(\lfloor\frac nT\rfloor,\lfloor\frac mT\rfloor)\sum_{d\vert T}d\mu^2(d)\mu(\frac Td)
\]
接下来考虑两个问题。
首先是如何预处理 \(S(n,m)\) :
如果我们考虑枚举 \((i+j)\) 的和,设 \(\large F(n)=\sum\limits_{i=1}^ni^k\):
\[\large S(n,m)=\sum\limits_{i=m+1}^{n+m}\sum\limits_{j=1}^ij^k-\sum\limits_{i=1}^{n}\sum\limits_{j=1}^i=\sum\limits_{i=m+1}^{n+m}F(i)-\sum\limits_{i=1}^{n}F(i)=\sum_{i=1}^{n+m}F(i)-\sum\limits_{i=1}^{n}F(i)-\sum\limits_{i=1}^{m}F(i)
\]
那么设 \(\large G(n)=\sum\limits_{i=1}^nF(i)\) ,有 \(\large S(n,m)=G(n+m)-G(n)-G(m)\)
于是我们直接线性筛每一个数的 \(k\) 次幂,然后做二阶前缀和即可得到 \(G\)。
第二个问题是处理 \(\large \sum\limits_{d\vert T}d\mu^2(d)\mu(\frac Td)\)
发现是 \(id*\mu^2*\mu\) ,根据狄利克雷卷积的性质,得到这也是个积性函数,设为 \(f\) 。
讨论一下线性筛需要的端点值之后,直接线性筛预处理即可。
最后柿子就是一个除法分块,直接做。
代码
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
#define ull unsigned long long
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define dep(i,y,x) for(int i=(y);i>=(x);i--)
const int N=2e7+5,M=2e5+5;
int n,m,prime[N],cnt;
unsigned int k;
unsigned int f[N],pre[N],Pow[N],Ans;
bitset<N>vis;
inline unsigned int QuickPow(unsigned int x,unsigned int y){
unsigned int res=1;
while(y){
if(y&1) res=res*x;
x=x*x;
y>>=1;
}
return res;
}
inline void GetPrimes(int d){
vis[1]=true;f[1]=pre[1]=Pow[1]=1;//对1进行定义
for(int i=2;i<=d;i++){
if(!vis[i]) prime[++cnt]=i,f[i]=(unsigned int)(i-1),Pow[i]=QuickPow((unsigned int)i,k);//对质数进行定义
pre[i]=pre[i-1]+f[i]*Pow[i];
for(int j=1;j<=cnt&&i*prime[j]<=d;j++){
vis[i*prime[j]]=true;
Pow[i*prime[j]]=Pow[i]*Pow[prime[j]];
if(i%prime[j]==0){
int tmp=i/prime[j];
if(tmp%prime[j]) f[i*prime[j]]=f[tmp]*(unsigned int)(-prime[j]);//对质数的若干次幂进行定义(一般由f[i]递推);
break;
}
f[i*prime[j]]=f[i]*f[prime[j]];//通过 f(n),f(m) 计算 f(nm)
}
}
for(int i=2;i<=d;i++) Pow[i]+=Pow[i-1];
for(int i=2;i<=d;i++) Pow[i]+=Pow[i-1];
return ;
}
inline unsigned int GetSum(int x){return Pow[x+x]-(Pow[x]+Pow[x]);}
signed main(){
int t;read(t);read(n),read(k);GetPrimes(n*2);
while(t--){
read(n);Ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
Ans+=GetSum((n/l))*(pre[r]-pre[l-1]);
}
write(Ans);putchar('\n');
}
return 0;
}