jzoj3775 因子的排列

描述

一天,小B学习了分解质因数的相关内容。他发现,一个数的质因子可以有许多不同的排列方式,例如20=2 * 2 * 5=2 * 5 * 2=5 * 2 * 2,
那么小B认为20的质因子有3种不同的排列方式。小B的同学现在有一个问题:如果一个整数的质因子的不同的排列方式的种类数为k,那么这个整数n(n>1)最小是多少?小B的同学一共有T个不同的k值,希望小B帮助这个同学解决问题。但是小B发现T太大了,并且给出的k值也相当大,因此小B向你求助。

输入

第一行,一个整数T。 接下来的T行,每行一个整数k。

输出

T行,每行一个整数,其中第i行的整数表示第i个k值对应的n的值。

样例输入

4
1
2
3
105

样例输出

2
6
12
720

数据范围:

对于30%的数据,1<n<=100000; 对于全部的数据,1<n<2^63 1<k<2^63,1<=T<=1000。

先推结论

对于一个数S可以分解为

S = x 1 a 1 ∗ x 2 a 2 ∗ . . . ∗ x n a n S=x_{1}^{a_{1}}*x_{2}^{a_{2}}*...*x_{n}^{a_{n}} S=x1a1x2a2...xnan

那么方案数就是=:(这里为方便表示设sum= x 1 + x 2 + . . + x n x_{1}+x_{2}+..+x_{n} x1+x2+..+xn)

F ( S ) = P s u m s u m P x 1 x 1 ∗ P x 2 x 2 ∗ . . . ∗ P x n x n F(S)=\frac{P_{sum}^{sum}}{P_{x_{1}}^{x_{1}}*P_{x_{2}}^{x_{2}}*...*P_{x_{n}}^{x_{n}}} F(S)=Px1x1Px2x2...PxnxnPsumsum

意思是sum个数全排列后分别除掉n种数各自内部的全排列,这样就可以得到排列方案。但我们不可能一个一个去求,所以考虑两种情况。

对于 T = S ∗ p r i m e [ i ] T=S*prime[i] T=Sprime[i]

如果S中已经有了 p r i m e [ i ] prime[i] prime[i] 那么新的方案数为

P s u m + 1 s u m + 1 P x 1 x 1 ∗ P x 2 x 2 ∗ . . . ∗ P x i + 1 x i + 1 ∗ . . . ∗ P x n x n \frac{P_{sum+1}^{sum+1}}{P_{x_{1}}^{x_{1}}*P_{x_{2}}^{x_{2}}*...*P_{x_{i}+1}^{x_{i}+1}*...*P_{x_{n}}^{x_{n}}} Px1x1Px2x2...Pxi+1xi+1...PxnxnPsum+1sum+1

那么可以用排列展开发现:

F ( T ) = F ( S ) ∗ ( s u m + 1 ) ∗ P x i x i P x i + 1 x i + 1 = F ( S ) ∗ s u m + 1 x i + 1 F(T)=F(S)*\frac{(sum+1)*P_{x_{i}}^{x_{i}}}{P_{x_{i}+1}^{x_{i}+1}}=F(S)*\frac{sum+1}{x_{i}+1} F(T)=F(S)Pxi+1xi+1(sum+1)Pxixi=F(S)xi+1sum+1

然后我们可以奇妙地发现:当S中没有 p r i m e [ i ] prime[i] prime[i]时,上述公式依然成立。

做法

其实做下来合法的方案也不是特别多,用到的最多只有15个质数,所以可以考虑打表。所以可以考虑预处理方案数对应最小的数字。哦哦,记得开long double。

最后说下dfs中部分变量的意思,mul是当前乘积,sol是当前乘积的方案数。

#include<bits/stdc++.h>
using namespace std;
#define ri register int
#define ll long long
#define double long double
const int N=50;
int n,prime[100005],not_prime[100005],tot;
int now,ans[N];
ll f1[1000005],f2[1000005];
double mx;
double target;
struct info{
	double x,y;
}f[1000005];
bool operator <(const info& a,const info& b){
	if(a.x==b.x)
		return a.y<b.y;
	return a.x<b.x;
}
inline void pre(){
	for(ri i=2;i<=100;++i){
		if(!not_prime[i]) prime[++tot]=i;
		for(ri j=1;j<=tot&&prime[j]*i<=100;++j){
			not_prime[prime[j]*i]=1;
			if(!(i%prime[j])) break;
		}
	}
}
inline void dfs(int kind,int sum,int up,double sol,double mul){
	if(mul>=mx||kind>15)
		return;
	for(ri i=1;i<=up;++i){
		mul*=prime[kind];
		sol=sol*(sum+i)/i;//这里就是推的结论
		if(mul>mx||sol>mx)
			return;
		f[++tot].x=sol;
		f[tot].y=mul;
		dfs(kind+1,sum+i,i,sol,mul);
	}
}
int main(){
	pre();
	mx=LONG_LONG_MAX;
	scanf("%d",&n);
	dfs(1,0,63,1,1);
	sort(f+1,f+tot+1);
	now=0;
	for(ri i=1;i<=tot;++i){
		if(f[i].x!=f[i-1].x)
			f1[++now]=(ll)f[i].x,f2[now]=(ll)f[i].y;
	}
	while(n--){
		ll k;
		scanf("%lld",&k);
		int pos=lower_bound(f1+1,f1+now+1,k)-f1;
		printf("%lld\n",f2[pos]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值