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 }