51nod 1742 开心的小Q (莫比乌斯函数)

题解:

  分析:- - 完全是看着题解还想半天才会做的。。纠正一个错误,题解中的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 }

 

posted @ 2017-05-27 13:02  7391_KID  阅读(683)  评论(0编辑  收藏  举报