题解:
分析:- - 完全是看着题解还想半天才会做的。。纠正一个错误,题解中的F(n)和S(n)中都应该是取整而不是下取整.首先S(n)的式子不难想到,问题就在于数据范围太大,强求会T掉.换一下求和顺序,枚举i/d,再枚举d,就可以将原式变形成一个对F(n)求和的式子,然后从1到n中,F(i)有重复,只需要计算一次再乘个数就行了,相当于做一个分块.然后求F(n)时又做了一个变换,可以这么理解:总共有n个数,减去无平方因子数即可,枚举i从1到n,减去每个数的平方倍数的个数,因为这些数一定有平方因子,再由容斥原理,加回被减两次的,以此类推...实际上i超过根号n时没有倍数小于n,所以i只需要到根号n.
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1e9+5,maxlen=32000; 7 int mu[maxlen],prinum[maxlen],len=0,a,b,f[maxlen]; 8 void CalPri(){ 9 int num[maxlen]; 10 for(int i=2;i<maxlen;i++)num[i]=i; 11 for(int i=2;i<maxlen;i++){ 12 if(num[i]==0)continue; 13 prinum[len++]=i; 14 mu[i]=-1; 15 for(int j=2*i;j<maxlen;j+=i) 16 num[j]=0; 17 } 18 } 19 //预处理前根号n个mu 20 void Calmu(){ 21 CalPri(); 22 mu[1]=1; 23 for(int i=2;2*i<=maxlen;i++){ 24 for(int j=0;j<len&&prinum[j]*i<maxlen;j++){ 25 if(i%prinum[j]==0){ 26 mu[prinum[j]*i]=0; 27 break; 28 } 29 mu[prinum[j]*i]=-mu[i]; 30 } 31 } 32 } 33 ll F(int n){ 34 if(n==0)return 0; 35 ll ans=n; 36 for(int i=1;i*i<=n;i++){ 37 ans-=mu[i]*(n/(i*i)); 38 } 39 return ans; 40 } 41 ll S(int n){ 42 ll ans=0,r,cnt=1; 43 for(int i=1;i<n&&cnt;i+=cnt){ 44 r=n/i; 45 cnt=n/r-n/(r+1); 46 ans+=cnt*F(r); 47 } 48 return ans; 49 } 50 //ll text(int n){ 51 // ll ans=0; 52 // for(int i=1;i<n;i++){ 53 // int r=n/i; 54 // ans+=F(r); 55 // } 56 // return ans; 57 //} 58 int main(){ 59 Calmu(); 60 // int n; 61 // cin>>n; 62 // cout<<S(n)<<' '<<text(n)<<endl; 63 // cout<<i<<' '<<F(i)<<endl; 64 cin>>a>>b; 65 cout<<S(b)-S(a-1)<<endl; 66 return 0; 67 }