素因子分解表+重复元素全排列问题
如果要求解重复运算的全排列问题,最朴素的方法是先求n!,再求重复元素m1,m2,m3的m1!,m2!,m3!,然后再做除法,但这样写很容易爆时间和爆空间。
所以这里聊一聊利用素因子分解表来降低时间复杂度。
一,素因子分解表
我们都知道,一个比1大的合数可以分解成若干个素数的乘积,比如6=23,4=22。
那么现在聊的素因子分解表是什么意思呢?
其作用就是记录每个数的素因数,它的结构如下:
{这个数的素因数个数,素因数1,素因数2,…,素因数n}
这个表可以是无限大,但因为我们最多计算到30!的值,所以只用记录1到30的数的素因数分解情况即可。
即:
int primes[31][5]=
{
{0},{0},{1,2},{1,3},{2,2,2},{1,5},{2,2,3},{1,7},
{3,2,2,2},{2,3,3},{2,2,5},{1,11},{3,2,2,3},{1,13},
{2,2,7},{2,3,5},{4,2,2,2,2},{1,17},{3,2,3,3},{1,19},
{3,2,2,5},{2,3,7},{2,2,11},{1,23},{4,2,2,2,3},{2,5,5},
{2,2,13},{3,3,3,3},{3,2,2,7},{1,29},{3,2,3,5}
};
二,怎么用素因数表来表示n!
n!=1X2X3X…Xn
所以我们只用从2开始分别表示当数即可。
即:
for(int i=2;i<s.length();i++)
{
for(int j=1;j<=primes[i][0];j++)
divide.pub(primes[i][j]);
}
这里要注意,因为素因子分解表的第一个元素是指素因子分解个数,所以我们要从primes[i][1]开始压入vector数组。
三,怎么用素因数本因素表示重复元素m1!,m2!,m3!
都说了重复元素,重复元素,那么首当其冲应该是找到重复元素的个数。
所以应该遍历一遍字符组找到重复元素个数:
for(int i=0;i<s.length();i++)alpha[s[i]-'a'];
之后就要找到m1!,m2!,m3!…的素因数分解。
即:
for(int i=0;i<26;i++)
{
for(int j=2;j<=alpha[i];j++)
{
for(int k=1;k<=primes[j][0];k++)
devisor.pub(primes[j][k]);
}
}
四,计算重复元素全排列的值
首先,我们先思考一下,n!/m1!*m2!*m3!..的值是不是一定是个整数?
可以这样想,全排类问题实际上是不同排列方式的总数,那么这么聊就不可能是小数。
所以在erase重复的项了之后就只剩n!的素因子了。
之后就可以通过累乘得出答案了。
即:
for(int i=0;i<devide.size();i++)sum*=devide[i];
全篇代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pub push_back
#define pob pop_back
int primes[31][5]=
{
{0},{0},{1,2},{1,3},{2,2,2},{1,5},{2,2,3},{1,7},
{3,2,2,2},{2,3,3},{2,2,5},{1,11},{3,2,2,3},{1,13},
{2,2,7},{2,3,5},{4,2,2,2,2},{1,17},{3,2,3,3},{1,19},
{3,2,2,5},{2,3,7},{2,2,11},{1,23},{4,2,2,2,3},{2,5,5},
{2,2,13},{3,3,3,3},{3,2,2,7},{1,29},{3,2,3,5}
};
int alpha[26]={0};
int main()
{
ios::sync_with_stdio(false);
vector<int>devide,devisor;
string s;
cin>>s;
for(int i=2;i<=s.length();i++)
{
for(int j=1;j<=primes[i][0];j++)
devide.pub(primes[i][j]);
}
for(int i=0;i<s.length();i++)alpha[s[i]-'a']++;
for(int i=0;i<26;i++)
{
for(int j=2;j<=alpha[i];j++)
for(int k=1;k<=primes[j][0];k++)
devisor.pub(primes[j][k]);
}
for(int i=0;i<devisor.size();i++)
{
for(int j=0;j<devide.size();j++)
{
if(devide[j]==devisor[i])
{
devide.erase(devide.begin()+j);
break;
}
}
}
ll sum=1;
for(int i=0;i<devide.size();i++)sum*=devide[i];
cout<<sum<<endl;
return 0;
}