10299:Relatives
問題文
http://uva.onlinejudge.org/external/102/10299.html
1以上でnより小さい、nと互いに素な数の個数を求めよ。
包除原理。
互いに素であるという事は共通素因数を持たないということ。
1からn-1のなかでこのような数の個数を求めればよい。
例えばn=30のとき、30=2*3*5だから1から29のなかで2も3も5も素因数に持たない数を数えればよい。
1から29までの整数で、
2の倍数の個数は29/2=14
3の倍数の個数は29/3=9
5の倍数の個数は29/5=5
2*3=6の倍数の個数は29/6=4
3*5=15の倍数の個数は29/15=1
2*5=10の倍数の個数は29/10=2
2*3*5=30の倍数の個数は29/30=0
よって、求める個数は
29-(14+9+5-(4+1+2-0))=8
nを素因数分解する。
素因数の種類はそれほど多くはならないので、どの素因数を使うかをビットで管理して↑のようなことをすればよい。
#include<iostream> #include<vector> #include<algorithm> #define all(c) (c).begin(),(c).end() using namespace std; vector<int> prime_factor(int n){ vector<int>res; for(int i=2;i*i<=n;i++){ if(n%i==0)res.push_back(i); while(n%i==0)n/=i; } if(n!=1)res.push_back(n); return res; } int main(void){ int n; while(cin >> n,n){ vector<int>a=prime_factor(n); int ans=n-1,al=a.size(); for(int S=1;S<(1<<al);S++){ int cnt=0,tmp=1; for(int i=0;i<al;i++){ if(S>>i&1)cnt++,tmp*=a[i]; } if(cnt%2)ans-=(n-1)/tmp; else ans+=(n-1)/tmp; } cout << ans << endl; } return 0; }