hdu 3501 Calculation 2

题目描述:求小于n且与n不互质的数的和。

分析:

  方法一:容斥原理。对n分解因式,利用容斥原理来n的因子的和即为答案。

  方法二:考虑欧拉函数,n之前与n互质的数的和sum=n*euler(n)/2

     如果gcd(n,i)=1,那么必有gcd(n,n-i)=1,所以与n互质的数应该是成对出现的,每一对的和就是n,所以总和就是n*euler(n)/2;

 

容斥原理解法

 1 #include<iostream>
 2 #include<cstring>
 3 #include<vector>
 4 #define N 1000010
 5 using namespace std;
 6 typedef long long ll;
 7 const ll mod=1000000007;
 8 bool p[N];
 9 ll s[N];
10 vector<ll>x;
11 void init(){
12     memset(p,1,sizeof(p));
13     for(int i=2;i*i<N;i++)
14         for(int j=i;i*j<N;j++)
15             p[i*j]=0;
16     s[0]=0;
17     for(int i=2;i<N;i++)
18         if(p[i])s[++s[0]]=i;
19 }
20 void div(ll n){
21     x.clear();
22     for(int i=1;s[i]*s[i]<=n;i++){
23         if(n%s[i]==0){
24             x.push_back(s[i]);
25             while(n%s[i]==0)n/=s[i];
26         }
27     }
28     if(n>1)x.push_back(n);
29 }
30 ll cal(ll a,ll n){
31     return (n/a)*(n-a)/2;
32 }
33 void solve(ll n){
34     div(n);
35     ll ans=0;
36     int c=x.size();
37     for(int i=1;i<(1<<c);i++){
38         int cnt=0,a=0,ii=i;
39         ll num=1;
40         while(ii>0){
41             if(ii&1){
42                 num*=x[cnt];
43                 ++a;
44             }
45             ii>>=1;
46             ++cnt;
47         }
48         ll count=cal(num,n);
49         if(a&1)ans=(ans+count);
50         else ans=(ans-count);
51     }
52     cout<<ans%mod<<endl;
53 }
54 int main(){
55     init();
56     ll n;
57     while(cin>>n){
58         if(!n)return 0;
59         solve(n);
60     }
61     return 0;
62 }

 

欧拉函数解法

 1 #include<iostream>
 2 #include<cstring>
 3 #define N 1000010
 4 using namespace std;
 5 typedef long long ll;
 6 const ll mod=1000000007;
 7 bool p[N];
 8 ll s[N];
 9 void init(){
10     memset(p,1,sizeof(p));
11     for(int i=2;i*i<N;i++)
12         for(int j=i;i*j<N;j++)
13             p[i*j]=0;
14     s[0]=0;
15     for(int i=2;i<N;i++)
16         if(p[i])s[++s[0]]=i;
17 }
18 ll euler(ll n){
19     ll ans=n;
20     for(int i=1;s[i]*s[i]<=n;i++){
21         if(n%s[i]==0){
22             ans/=s[i];
23             ans*=(s[i]-1);
24             while(n%s[i]==0)n/=s[i];
25         }
26     }
27     if(n>1){
28         ans/=n;
29         ans*=(n-1);
30     }
31     return ans;
32 }
33 int main(){
34     init();
35     ll n;
36     while(cin>>n){
37         if(!n)return 0;
38         ll ans=n*(n-1)/2;
39         cout<<(ans-euler(n)*n/2)%mod<<endl;
40     }
41     return 0;
42 }
posted @ 2012-10-28 21:22  silver__bullet  阅读(252)  评论(0编辑  收藏  举报