虽然都写了,过也过了,还是觉得杜教筛的复杂度好玄学
设f*g=h,∑f=S,
则∑h=∑f(i)S(n/i下取整)
把i=1时单独拿出来,得到
S(n)=(∑h-∑2->n f(i)S(n/i下取整)
右边的部分可以分块解决
递归一下,≤一个阈值的暴力表出来
注意阈值以上的也要记忆化
复杂度不会算,但从本题来看过1e10没问题
1 #include <bits/stdc++.h> 2 #define MAX 5000000 3 using namespace std; 4 long long a,b,N; 5 long long miu[MAX+1],p[MAX],ans[MAX]; 6 bool bo[MAX+1]; 7 long long work(long long n) 8 { 9 if(n<=MAX) return miu[n]; 10 if(ans[N/n]) return ans[N/n]; 11 long long ret=1; 12 for(long long j=2;j<=n;) 13 { 14 long long nex=n/(n/j); 15 ret-=(nex-j+1)*work(n/j); 16 j=nex+1; 17 } 18 ans[N/n]=ret; 19 return ret; 20 } 21 int main() 22 { 23 int sum=0;miu[1]=1; 24 for(int i=2;i<=MAX;i++) 25 { 26 if(!bo[i]) 27 p[++sum]=i,miu[i]=-1; 28 for(int j=1;j<=sum;j++) 29 { 30 if((long long)p[j]*i<=MAX) 31 { 32 bo[p[j]*i]=1; 33 miu[i*p[j]]=-miu[i]*(bool)(i%p[j]); 34 } 35 else break; 36 if(i%p[j]==0) break; 37 } 38 } 39 for(int i=2;i<=MAX;i++) 40 miu[i]+=miu[i-1]; 41 scanf("%lld%lld",&a,&b); 42 N=b; 43 long long ans1=work(b); 44 for(int i=1;i<=MAX;i++) 45 ans[i]=0; 46 N=a-1; 47 long long ans2=work(a-1); 48 printf("%lld ",ans1-ans2); 49 return 0; 50 }