版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86553725
BZOJ传送门
洛谷传送门
SPOJ传送门
解析:
重温开通博客之前写的一些数学题。
现在还是推了我一段时间的。
思路:
首先我们并不擅长处理 问题,所以一律换成
接下来需要巧妙的转化:
由于 ,(不要告诉我你不会 求 )
所以我们进一步化简:
现在我们只需要考虑怎么求这个东西:
套路:枚举
。。。
。。。
。。。
这么明显的欧拉函数woc。。。
我们只需要筛出欧拉函数,然后枚举倍数加到该加的地方,复杂度是调和级数。相当于 。
然后就可以 回答每个询问了
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
}
using namespace IO;
cs int P=1000006;
int phi[P],prime[P],pcnt;
bool mark[P];
ll ans[P];
inline void linear_sieves(int len=P-6){
phi[1]=1;
for(int re i=2;i<=len;++i){
if(!mark[i])prime[++pcnt]=i,phi[i]=i-1;
for(int re j=1;i*prime[j]<=len;++j){
mark[i*prime[j]]=true;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int re i=1;i<=len;++i)
for(int re j=2;j*i<=len;++j)ans[i*j]+=(ll)j*phi[j];
for(int re i=1;i<=len;++i)ans[i]=ans[i]*i/2+i;
}
signed main(){
linear_sieves();
for(int re T=getint();T--;pc('\n'))outint(ans[getint()]);
return 0;
}