AcWing 1295. X的因子链
X的因子链
解题思路:
这一题要我们求最长的长度还有对应长度的个数。
首先我们要知道因子链是怎么组成的。(注意这是一条链)
我们只要在每一个数字之前乘以另一个因子这样就能满足题目的要求了。
所以因子链的长度就可以理解为有多少个因子的总和
映射过后x的所有质因子的排列数
区分:约数的个数和因子的个数。
同时在算约数个数的时候,是不可能出现选了几个2能代替几个三的情况。因为是出现不了交集的
那么一共有多少个因子呢?最多有20个因子,因为20个因子的时候已经是最大的数字了,全是2的话都只有20个因子
在算出了因子的个数的全排列数之后
然后再除以每个数字的全排列数
这个就是多重集合的排列数问题
然后longlong的话是2^63 -1 64位整数,但是第一位是符号位置
y总的代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = (1 << 20) + 10;
int primes[N], cnt; // prime存所有的质数,cnt有多少个质数
int minp[N];
bool st[N]; // st是一个bool值,看看有没有被筛选过
void get_primes(int n) // get_primes(n)1-n有哪些是质数
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) // 当前的数没有被筛选过,即没有质因子
{
minp[i] = i;
primes[cnt ++ ] = i; // 把质数存起来
}
for (int j = 0; primes[j] * i <= n; j ++ ) // 从小到大枚举所有的质数
{
/* 合数N是否一定会被筛掉,答案是会的因为。假设P为N最小的质因子。把N拆分成P和N/P,然后P是肯定小于N/P的最小质因子,因为N/P也是N的一个因子,如果它拆解出来的因子比P小,假设就不成立了。当i取到N/P的时候,Pj一定是小于等于N/P的最小质因子,所以N被筛掉了
*/
// 因为每个数的最小质因子只有一个所以只会被筛选一次
int t = primes[j] * i;
st[t] = true; // 把质数的i倍筛掉,筛掉的一定是合数
minp[t] = primes[j];
if (i % primes[j] == 0) break; // prime[j]一定是小于等于i的最小质因子,用它的最小质因子筛选的
}
}
}
int main()
{
get_primes(N - 1);
int fact[30], sum[N];
int x;
while (scanf("%d", &x) != -1)
{
int k = 0, tot = 0;
while (x > 1)
{
int p = minp[x];
fact[k] = p, sum[k] = 0;
while (x % p == 0) // x是p的倍数
{
x /= p;
sum[k] ++ ;
tot ++ ;
}
k ++ ;
}
LL res = 1;
for (int i = 1; i <= tot; i ++ ) res *= i;
for (int i = 0; i < k; i ++ )
for (int j = 1; j <= sum[i]; j ++ )
res /= j;
printf("%d %lld\n", tot, res);
}
return 0;
}
自己的代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100 + 10;
int p[maxn], c[maxn];
void get_divisors(int x, int &cnt, int &tot)
{
memset(p, 0, sizeof p);
memset(c, 0, sizeof c);
for(int i = 2; i <= x / i; i++)
{
if(x % i == 0)
{
while(x % i == 0)
{
p[cnt] = i;
c[cnt] ++;
x /= i;
tot ++;
}
cnt ++;
}
}
if(x > 1){p[cnt] = x,c[cnt] = 1;tot++;cnt++;}
}
int main()
{
int x;
while(~scanf("%d", &x) && x)
{
int cnt = 0, tot = 0;
get_divisors(x, cnt, tot);
LL res = 1;
for(int i = 1; i <= tot; i++) res*= i; // 从1开始
for(int i = 0; i < cnt; i++)
for(int j = 1; j <= c[i]; j++)
res /= j;
printf("%d %lld\n", tot, res);
}
}
有什么问题可以加qq:1281372141进行交流