细胞分裂【唯一分解定理】
题目链接:https://ac.nowcoder.com/acm/contest/1106/B
题目大意:
1.依次给出n,m1,m2,si。m1的m2次方代表一个值A,求在n个si中,各个si的x次方是A的倍数,x的最小值。
题解思路:
1.对m1进行质因数分解,得到每个质因子的次方,次方乘个m2即得到m1^m2的质因数分解结果。
2.枚举si,对于每一个si,若其没有包含m1^m2所有的质因数,则任si次方增长也无法达到m1^m2的倍数。若包含了m1^m2的所有质因数,则只需要求这些质因数 在m1^m2中的次方比上在si中的次方,向上取整,取其中的最大值。(意为si达到m1 ^m2的倍数至少需要增加的次方数)。结果是对于每一个si的结果取最小值。
代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 #define mem(a, b) memset(a, b, sizeof(a)) 6 const int inf = 0x3f3f3f3f; 7 using namespace std; 8 9 int n, m1, m2, cnt; 10 int s[10010], vis[30010], a[30010], b[30010]; //a存质因子,b存该质因子的次数 11 int prime[30010]; 12 13 void get_prime(int n) //得到2~m1范围内所有的素数 14 { 15 mem(vis, 1), cnt = 0; 16 for(int i = 2; i <= n; i ++) 17 { 18 if(vis[i]) 19 { 20 prime[++ cnt] = i; 21 for(int j = i; j <= n; j += i) 22 vis[j] = 0; 23 } 24 } 25 } 26 27 int main() 28 { 29 int n; 30 scanf("%d%d%d", &n, &m1, &m2); 31 for(int i = 1; i <= n; i ++) 32 scanf("%d", &s[i]); 33 if(m1 == 1) 34 printf("0\n"); 35 else 36 { 37 get_prime(m1); 38 int x = m1, k = 0; //k是质因子数量 39 for(int i = 1; i <= cnt; i ++) 40 { 41 if(x % prime[i] == 0) 42 { 43 k ++; 44 a[k] = prime[i]; 45 int p = 0; //该质因子次数 46 while(x % prime[i] == 0) 47 { 48 p ++; 49 x /= prime[i]; 50 } 51 b[k] = p * m2; //得到m1 ^ m2的所有质因数以及次方 52 } 53 if(x == 1) 54 break; 55 } 56 int ans = inf; 57 for(int i = 1; i <= n; i ++) 58 { 59 int maxx = 0; 60 for(int j = 1; j <= k; j ++) 61 { 62 if(s[i] % a[j]) //若s[i]没有包含m1 ^ m2的所有质因数,则去除掉 63 { 64 maxx = inf; 65 break; 66 } 67 int p = 0, x = s[i]; 68 while(x % a[j] == 0) 69 { 70 x /= a[j]; 71 p ++; 72 } 73 int temp = ceil(b[j] * 1.0 / p); //注意向上取整时,转化成浮点型计算,否则整形/整形依然是整形,没有达到向上取整的作用 74 maxx = max(maxx, temp); 75 } 76 ans = min(ans, maxx); 77 } 78 if(ans == inf) 79 printf("-1\n"); 80 else 81 printf("%d\n", ans); 82 } 83 return 0; 84 }
扩展:
该解法用于,求解一个数B的最小次方x是A的倍数,求x。(当A是m1^m2型很大的数据时,B的次方也很大时)。