1. 程式人生 > >POJ 1091 容斥原理

POJ 1091 容斥原理

.org 質因子 blank dfs tar cin href strong 元組

鏈接:

http://poj.org/problem?id=1091

題意:

給你兩個正整數n,m,讓你求長度為n+1的滿足條件的一個等式:a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*x(n+1)=1 (0<=a[i]<=m&&a[n+1]=m)

讓你求一共有多少種情況滿足這個條件。

要使得 a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*m=1 (0<=a[i]<=m),那麽a[1],a[2],a[3]....a[n+1]的最大公約數為1.

題解:

要解決此題,你需要知道的知識有擴展歐幾裏得,鴿巢原理,以及遞歸求所有的排列組合。

許多博客都舉了這麽一個例子:

例如:n=2,m=360
360=3^2*2^3*5 所有不滿足條件的數列,最大公約數是360質因子的乘積,只要將這些組合去掉,就是要求的答案(不懂的慢慢揣摩)

那麽就要先求出m的所有質因子,然後求出總的排列組合的個數,即題目中說的M^N,最後根據鴿巢原理求得最後答案。

公式為:ans=M^N-(有奇數個公因數的n元組)+(有偶數個公因數的n元組)。拿上面的例子來說就是

ans=m^n-( 有公因數2的n元組)- (有公因數3的n元組)- (有公因數5的n元組)+ (有公因數2,3的n元組) +(有公因數2,5的n元組)+ (有公因數3,5的n元組)- (有公因數2,3,5的n元組).

有公因數d的n元組,每個位置上有 (m/d)個選擇(1 ~ m裏面有m/d個d的倍數),根據乘法原理,可以得出有公因數d的n元組有 (m/d)^n 個.

代碼:

31 ll factor[100], sz;
32 
33 void prime_factor(ll n) {
34     for (ll i = 2; i*i <= n; i++) if (n%i == 0) {
35         factor[sz++] = i;
36         while (n%i == 0) n /= i;
37     }
38     if (n > 1) factor[sz++] = n;
39 } 40 41 ll mod_pow(ll x, ll n) { 42 ll res = 1; 43 while(n) { 44 if (n & 1) res *= x; 45 x *= x; 46 n >>= 1; 47 } 48 return res; 49 } 50 51 ll n, m; 52 ll p[100], sum; 53 54 void dfs(ll id, ll step, ll num) { 55 if (step == num) { 56 ll x = m; 57 rep(i, 0, num) x /= p[i]; 58 sum += mod_pow(x, n); 59 return; 60 } 61 rep(i, id, sz) { 62 p[step] = factor[i]; 63 dfs(i + 1, step + 1, num); 64 } 65 } 66 67 int main() { 68 cin >> n >> m; 69 prime_factor(m); 70 ll ans = mod_pow(m, n); 71 rep(i, 1, sz + 1) { 72 sum = 0; 73 dfs(0, 0, i); 74 if (i & 1) ans -= sum; 75 else ans += sum; 76 } 77 cout << ans << endl; 78 }

POJ 1091 容斥原理