[bzoj3944] Sum
Description
Input
一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问
Output
一共T行,每行两个用空格分隔的数ans1,ans2
Sample Input
6
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
solution
杜教筛模板题无敌卡常题.
先搬出套路式子:
\[S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
\]
对于\(\mu(n)\),拿一个\(I(n)=1\)和他卷起来,可以得到:
\[S(n)=1-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)
\]
对于\(\varphi(n)\),同样拿一个\(I(n)\)卷起来,得到:
\[S(n)=\frac{n*(n+1)}{2}-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)
\]
然后飞速的敲完代码,提交,\(TLE\)......
可能是我太弱了,所有的卡常技巧都用上了,然而并没有什么用....
然后突然发现一个这样的事情:
对于\(\varphi(n)\),其实可以写成这个样子:
\[\varphi(n)=\sum_{i=1}^{n}\epsilon(\gcd(i,n))
\]
其中\(\epsilon(n)=[n=1]\).
然后苦思冥想无果后闲着无聊对前缀和反演下:
\[\begin{align}
S(n)&=\sum_{i=1}^{n}\sum_{d=1}^i\epsilon(\gcd(d,i))\\
&=\sum_{i=1}^{n}\sum_{d=1}^i\sum_{d_1|i\&d_1|d}\mu(d_1)\\
&=\sum_{i=1}^{n}\sum_{d_1|i}\sum_{d=1}^{\frac{i}{d_1}}\mu(d_1)\\
&=\sum_{i=1}^n\sum_{d_1|i}\mu(d_1)\frac{i}{d_1}\\
&=\sum_{d_1=1}^n\sum_{i=1}^{\frac{n}{d_1}}\mu(d_1)*i\\
&=\sum_{d_1=1}^n\mu(d_1)*\frac{\lfloor\frac{n}{d_1}\rfloor(\lfloor\frac{n}{d_1}\rfloor+1)}{2}
\end{align}
\]
然后惊奇的发现,这里面用到的\(\mu(n)\)的前缀和正好是第二问要求的,然后这么一来直接快了一倍不止,成功的只跑了\(6sAC\)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) x=-x,putchar('-');
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 3e6+1;
int pri[maxn],vis[maxn],n,tot,inv2,inv6,mu[maxn];
void sieve() {
mu[1]=1;
for(int i=2;i<maxn;i++) {
if(!vis[i]) pri[++tot]=i,mu[i]=-1;
for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) {
vis[t=i*pri[j]]=1;
if(!(i%pri[j])) {mu[t]=0;break;}
mu[t]=-mu[i];
}
}
//for(int i=1;i<maxn;i++) phi[i]=phi[i-1]+phi[i];
for(int i=1;i<maxn;i++) mu[i]=mu[i-1]+mu[i];
}
map<int,int > Mu;
/*ll sum_phi(int n) {
if(n<maxn) return phi[n];
if(Phi[n]) return Phi[n];
ll T=2,res=1ll*n*(n+1)/2;
while(T<=n) {
ll pre=T;T=n/(n/T);
res=res-1ll*(T-pre+1)*sum_phi(n/T);T++;
}
return Phi[n]=res;
}*/
ll sum_mu(ll n) {
if(n<maxn) return mu[n];
if(Mu[n]) return Mu[n];
ll T=2,res=1;
while(T<=n) {
ll pre=T;T=n/(n/T);
res=res-1ll*(T-pre+1)*sum_mu(n/T);T++;
}
return Mu[n]=res;
}
ll sum_phi(ll n) {
ll T=1,ans=0;
while(T<=n) {
ll pre=T;T=n/(n/T);
ans+=1ll*(n/pre)*(n/pre+1)/2*(1ll*sum_mu(T)-1ll*sum_mu(pre-1));
//printf("%lld %lld\n",1ll*sum_mu(T)-1ll*sum_mu(pre-1));
T++;
}
return ans;
}
signed main() {
int t,n;read(t);sieve();
while(t--) read(n),printf("%lld %lld\n",sum_phi(n),sum_mu(n));
//cerr << (double) clock()/1e6 << endl;
}