题目分析:
大意:给定一个数X(X<=2^20),题干给定数列:1 = X0, X1, X2, …, Xm = X
且要求数列 ①Xi<X(i+1);②Xi | X(i+1) 即Xi 整除 X(i+1)。
求符合要求的最大长度的数列,输出这种数列的长度(不计算X0=1)及个数。
例:X=10 则符合要求的最大长度的数列为:1、2、10 或1、5、10,则最大长度为2,个数为2。
X=100 则符合要求的最大长度的数列为:1、2、10、20、100 ,
1、2、4、20、100,
1、5、10、20、100,
1、5、25、50、100;
则最大长度为4,个数为4。
思路:运用唯一分解定理将X分解。X=a1^p1 * a2^p2 *……ai^pi;
符合要求的数列的①最大长度为L=(p1+p2+……+pi);
②个数为p1个a1、p2个a2……能组合成多少种数列。(答案为 L!/(p1!+p2!+……))
【第②问用到组合数学的知识:3、3、5、5、5这五个数有多少种排列方式?其中相等的数是无差别的,答案就是上面的公式;D=5!/(2!+3!)】
再拿X=100为例:100=(2^2) * (5^2);则长度L=2+2=4,个数D=4!/(2!+2!)=6;
附AC代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <vector> #define maxn 1100000 typedef long long int ll; using namespace std; int prime[maxn]; bool vis[maxn]; int num; void init_prime() //筛选素数 { memset(vis,false,sizeof(vis)); memset(prime,0,sizeof(prime)); num=1; for(int i=2; i<maxn; i++) { if(vis[i]==false) prime[num++]=i; for(int j=1; j<=num&&(prime[j]*i<maxn); j++) { if(i%prime[j]==0) break; vis[prime[j]*i]=true; } } } vector<int > v; int L=0; void Dint(int x) //唯一分解定理 { for(int i=1; i<=num; i++) { if(x%prime[i]==0) { int cnt=0; while(x%prime[i]==0) { cnt++; x/=prime[i]; } L+=cnt; v.push_back(cnt); } if(x==1) break; } if(x!=1) { v.push_back(1); L++; } return; } ll Fi[30]; //必须是long long void init() // 求1~20 的阶乘 存在Fi数组里 { Fi[1]=1; for(int i=2; i<22; i++) { Fi[i]=Fi[i-1]*i; } } ll D; void solve() //the number of chains of such length. { D=Fi[L]; for(int i=0; i<v.size(); i++) { D=D/Fi[v[i]]; } } int main() { int n; init_prime(); init(); while(scanf("%d",&n)!=EOF) { L=0; v.clear(); Dint(n); solve(); printf("%d %lld\n",L,D); } return 0; }