BZOJ 3944 Sum
杜教筛第一道题!
题面:
3944: Sum
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3843 Solved: 1030
[Submit][Status][Discuss]
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
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
2 0
22 -2
58 -3
278 -3
1655470 2
HINT
反演+杜教筛。
$1=\sum_{i=1}^{n}\sum_{d|i}\mu(d)=\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)=\sum_{i=1}^{n}S(\lfloor\frac{n}{i}\rfloor)$
$\therefore S(n)=1-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)$
$S(n)=\sum_{i=1}^{n}\varphi(i)=\sum_{i=1}^{n}[i-\sum_{d|i,d<i}\varphi(d)]=\frac{n(n+1)}{2}-\sum_{i=2}^{n}\sum_{d|i}\varphi(d)=\frac{n(n+1)}{2}-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)$
之后预处理前$\frac{2}{3}$,分块回答询问(记忆化搜索)。
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define LL long long 6 #define maxn 5400000 7 #define maxm 100000 8 #define uint unsigned int 9 int T,n; 10 int p[670000],cnt; 11 LL mu[maxn+1],varphi[maxn+1]; 12 LL ans_mu[maxm+1],ans_varphi[maxm+1]; 13 bool book[maxn+1],quest_mu[maxm+1],quest_varphi[maxm+1]; 14 void init() 15 { 16 mu[1]=1; 17 varphi[1]=1; 18 for(int i=2;i<=maxn;i++) 19 { 20 if(!book[i]) 21 { 22 mu[i]=-1; 23 varphi[i]=i-1; 24 p[++cnt]=i; 25 } 26 for(int j=1;j<=cnt&&1LL*p[j]*i<=maxn;j++) 27 { 28 book[i*p[j]]=true; 29 if(i%p[j]) 30 { 31 mu[i*p[j]]=-mu[i]; 32 varphi[i*p[j]]=varphi[i]*(p[j]-1); 33 } 34 else 35 { 36 mu[i*p[j]]=0; 37 varphi[i*p[j]]=varphi[i]*p[j]; 38 break; 39 } 40 } 41 } 42 for(int i=2;i<=maxn;i++) 43 mu[i]+=mu[i-1],varphi[i]+=varphi[i-1]; 44 } 45 LL questmu(uint now) 46 { 47 if(now<=maxn) 48 return mu[now]; 49 int last=n/now,nex; 50 if(quest_mu[last]) 51 return ans_mu[last]; 52 LL save=1; 53 for(uint i=2;i<=now;i=nex+1) 54 { 55 nex=now/(now/i); 56 save-=questmu(now/i)*(nex-i+1); 57 } 58 quest_mu[last]=true; 59 ans_mu[last]=save; 60 return save; 61 } 62 LL questvarphi(uint now) 63 { 64 if(now<=maxn) 65 return varphi[now]; 66 int last=n/now,nex; 67 if(quest_varphi[last]) 68 return ans_varphi[last]; 69 LL save=(LL)now*(now+1)>>1; 70 for(int i=2;i<=now;i=nex+1) 71 { 72 nex=now/(now/i); 73 save-=questvarphi(now/i)*(nex-i+1); 74 } 75 quest_varphi[last]=true; 76 ans_varphi[last]=save; 77 return save; 78 } 79 int main() 80 { 81 init(); 82 scanf("%d",&T); 83 while(T--) 84 { 85 scanf("%d",&n); 86 memset(quest_mu,false,sizeof(quest_mu)); 87 memset(quest_varphi,false,sizeof(quest_varphi)); 88 printf("%lld %lld\n",questvarphi(n),questmu(n)); 89 } 90 } 91