POJ1091跳蚤(容斥 + 唯一分解 + 快速幂)
题意:规定每次跳的单位 a1, a2, a3 …… , an, M,次数可以为b1, b2, b3 …… bn, bn + 1, 正好表示往左,负号表示往右, 求能否调到左边一位,即 a1* b1+ a2 * b2 + a3 * b3 + …… + m * (bn + 1) = 1;
根据欧几里得,则a1, a2 a3 …… an, m 最大公约数为1,m已知且a1, a2, a3 …… an 均小于等于m, 一共有m ^ n可能, 将m 唯一分解之后, 假设m = 2 * 3 * 5, 则不大于m且包含2因子的 共 m / 2, 包含3的 为 m/ 3, 容斥
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 using namespace std; 6 const int Max = 10000 + 10; 7 typedef long long LL; 8 LL n, m; 9 int prime[Max + 10], vis[Max + 10], tot; 10 LL em[100], a[100], cnt; 11 LL res; 12 void getPrime() 13 { 14 tot = 0, cnt = 0; 15 memset(vis, 0, sizeof(vis)); 16 for (int i = 2; i <= Max; i++) 17 { 18 if (!vis[i]) 19 { 20 prime[tot++] = i; 21 for (int j = i; j <= Max / i; j++) 22 vis[i * j] = 1; 23 } 24 } 25 26 } 27 void getfactor(int b) 28 { 29 memset(em, 0, sizeof(em)); 30 for (int i = 0; i < tot; i++) 31 { 32 if (prime[i] > b) 33 break; 34 if (b % prime[i] == 0) 35 { 36 em[cnt++] = prime[i]; 37 while (b % prime[i] == 0) 38 { 39 b /= prime[i]; 40 } 41 } 42 } 43 if (b > 1) 44 em[cnt++] = b; 45 } 46 LL Pow(LL a, LL b) 47 { 48 LL ans = 1; 49 while (b > 0) 50 { 51 if (b & 1) 52 ans *= a; 53 b >>= 1; 54 a *= a; 55 } 56 return ans; 57 } 58 void dfs(int cur, int num, int Cnt) // cur当前位置, num当前已包含个数,Cnt目标个数 59 { 60 if (num == Cnt) 61 { 62 //达到目标个数时, 用 m 去除以 所有包含的数 63 LL u = m; 64 for (int i = 0; i < num; i++) 65 u /= a[i]; 66 res += Pow(u, n); 67 return; 68 } 69 for (int i = cur; i < cnt; i++) 70 { 71 a[num] = em[i]; 72 dfs(i + 1, num + 1, Cnt); 73 } 74 return; 75 } 76 int main() 77 { 78 getPrime(); 79 while (scanf("%I64d%I64d", &n, &m) != EOF) 80 { 81 getfactor(m); 82 LL sum = Pow(m, n); 83 for (int i = 1; i <= cnt; i++) // 枚举每一个组合,i表示每个组合中数的个数 84 { 85 res = 0; 86 dfs(0, 0, i); 87 if (i & 1) 88 sum -= res; 89 else 90 sum += res; 91 } 92 printf("%I64d\n", sum); 93 } 94 95 return 0; 96 }