标签:and href cas inter 序列 分解 iter 假设 ack
Given a positive integer X, an X-factor chain of length m is a sequence of integers,
1 = X0, X1, X2, …, Xm = X
satisfying
Xi < Xi+1 and Xi | Xi+1 where a | b means a perfectly divides into b.
Now we are interested in the maximum length of X-factor chains and the number of chains of such length.
The input consists of several test cases. Each contains a positive integer X (X ≤ 220).
For each test case, output the maximum length and the number of such X-factors chains.
2 3 4 10 100
1 1 1 1 2 1 2 2 4 6
上来就是递推,然后超时了,果然有简单的解法,我们知道,一个合数总能拆成n个质数的积,如果是质数,那么也是它本身,我们假设拆出来的质数集合A中,A1, A1*A2, A1*A2*A3这样一直乘下去,最后一项一定会是X本身,并且由于都是质数,所以不可能再次分解,由于拆分的结果唯一,那么这一定是最长的链子了(因为一个数只能拆成一堆质数,且拆法唯一,那么这堆质数不可能再分解下取,如果拆成别的可能,那么就一定有一个合数,把这个合数拆分成质数,就是之前的全质数的拆法,所以全质数的拆法一定是最长的)
于是乎答案的第一项就是这些质数和的个数和(有些例如20可以拆成2个2一个5,相当于集合中有2个2,一个5,一共三个数,和为3),第二项就相当于这些的全排列,因为不管他们的排列顺序是怎么样的,最后都是(设Ai为排列完的第i项):A1,A1*A2,A1*A2*A3...,(其中A1-Am可以相等)这样才算满足题意的X序列,不管A1,A2哪个大,A1一定小于A1*A2且能被A1*A2整除。而根据排列组合中全排列P=集合个数的阶乘/(每个元素出现个数的阶乘),例如20=2*2*5,就是3!/(2!*1!)(因为2这个元素出现了两次,5出现了一次),这是因为当全排列的时候我们假定两个2是不一样的才有3!,但是实际上两个二如果位置互换其他情况不变产生的排列也是一样的,只有1/2的是不一样,如果存在多个元素出现不同次数,我们可以理解成,我先假定只有第一个元素有n1个,那么我们只要全排列的1/n1,在这些里面我们关注第二个元素有n2个,而在1/n1中也只有1/n2是不相同的(此时只考虑第一个和第二个元素的相同情况),以此类推,直到考虑所有的元素有多个的情况就是P=元素个数(不管是否重复只要有一个元素就算一个)的阶乘/每个元素(这里的元素是不重复的元素)的个数的阶乘。
如果还是不太清楚,我们拿20举例子,20可以化成2*2*5,也可以写成2^2*5^1,那么P=不重复的每个元素的幂之和的阶乘/每个不重复元素的幂的阶乘,P=(2 + 1)!/(2!*1!)
AC代码(思路借鉴:https://www.cnblogs.com/VBEL/p/11441686.html):
#include <stdio.h> #include <algorithm> #include <vector> #include <math.h> using namespace std; vector<int> v; bool is_prime[1050005]; long long ans, times; int q; void prime_factor(int q)//计算每个不重复元素幂之和,保存每个不重复元素的幂的值在v里面 { for(int i = 2; i <= sqrt(q); i++)//从2到sqrt遍历质数 { if(!is_prime[i]) continue; int time = 0; while(q % i == 0)//一个质数可能的幂可能不为1 { time++; q /= i; } if(time) { ans += time; v.push_back(time); } } if(q != 1)//如果q!=1就说明存在比sqrt(q)大的质数也是在拆分的集合中的,由于最多只存在一个(因为两个的话,乘积就会大于q),如果q!=1就说明存在,加入到v中 { ans++; v.push_back(1); } } long long factorial(int x)//计算阶乘 { long long temp = 1; for(int i = 2; i <= x; i++) temp *= i; return temp; } int main(void) { fill(is_prime, is_prime + 1050005, 1);/筛法求质数 is_prime[1] = false; for(int i = 2; i <= 1050000; i++) { if(is_prime[i]) { for(int j = 2 * i; j <= 1050005; j += i) is_prime[j] = false; } } while(scanf("%d", &q) != EOF) { ans = 0; v.clear(); prime_factor(q);//计算幂之和 times = factorial(ans);//幂之和的阶乘 for(vector<int>::iterator it = v.begin(); it != v.end(); it++) { times /= factorial(*it);//除以每个不重复的数的幂的阶乘 } printf("%lld %lld\n", ans, times); } return 0; }
挑战程序设计竞赛2.6习题:X-factor Chains POJ - 3421
标签:and href cas inter 序列 分解 iter 假设 ack
原文地址:https://www.cnblogs.com/jacobfun/p/12291567.html