能量球 (enb.pas/c/cpp)
题目描述
sideman 有着一个你们所不知道的秘密。实际上, sideman不是地球人,而是遥远的Gliese 行星的生物。sideman 虽然身在地球,但是时刻盼望着能够回到Gliese 去。终于有一天, sideman得到了几颗蕴含着无数能量的能量球。经过漫长艰苦的研究, sideman 搞清楚了这些能量球的规律。首先,能量球上面有一个正整数N,运用激发手段可以使得能量球上的正整数变为原来的数的一个真因子( A 是B 的一个真因子,等价于B 是A 的整数倍且0<A<B),并且放出单位数量的能量。当然,变为哪一个真因子是可以自由选择的。现在sideman 想知道每颗能量球最多可以放出多少能量,以及有多少种方式达到这个目的(两种操作方式被认为是不同的,当且仅当它们的操作序列中存在不同的真因子)。
分析:
首先,我们对一个数进行质因数分解,能量数就是它的质因数,所以对一个是进行质因数分解,但是数据的范围为10^9,但我们可以循环到sqrt(n),这样我们可以求出n的质因数,(但一个数是质因数时,我们可以看当n mod 它1 到n的质因数后,若这个数还是>1,那么它是质因数,他的质因数个数+1);那么它的方案数呢?若我们知道他的所有质因数后,将这些质因数拼成因数,所以方案数就是组合数,ans=n!/(a1!*a2!.....),先分组后分配。(可以先处理出阶乘,也可以一起算,一边乘一边除)。
注意,当n=0时,能量为0,但这也算一种方案,所以方案是为1。
代码实现:
program
exam;
const
p=1000000000;
var
i,j:longint;
ans,i1,total,t,k:int64;
a,a1:array[1..400000] of int64;
c:array[1..400000] of int64;
jj:array[0..30] of int64;
b:array[1..4000000] of boolean;
begin
assign(input,‘enb.in‘);
reset(input);
assign(output,‘enb.out‘);
rewrite(output);
t:=0;
while not eof do
begin
inc(t);
readln(a[t]);
end;
for i:=1 to 20 do
begin
jj[i]:=1;
for j:=1 to i do
jj[i]:=jj[i]*j;
end;
fillchar(b,sizeof(b),true);
for i:=2 to trunc(sqrt(p)) do
if b[i]=true then
begin
k:=trunc(sqrt(p)) div i;
for j:=2 to k do
begin
i1:=i*j;
b[i1]:=false;
end;
end;
for i:=1 to t do
begin
total:=0;
ans:=1;
a1:=a;
fillchar(c,sizeof(c),0);
for j:=2 to trunc(sqrt(a[i])) do
if (a1[i] mod j=0) and (b[j]=true) then
repeat
inc(total);
inc(c[j]);
a1[i]:=a1[i] div j;
until a1[i] mod j<>0;
if a1[i]>1 then
inc(total);
ans:=jj[total];
for j:=1 to trunc(sqrt(a[i])) do
if c[j]>1 then
ans:=ans div jj[c[j]];
if total=0 then
writeln(0,‘ ‘,1)
else
writeln(total,‘ ‘,ans);
end;
close(input);
close(output);;
end.