您的位置首页快问快答

noip2009的

noip2009的

的有关信息介绍如下:

noip2009的

Problem 3: cell 细胞分裂

【分析】

仔细读题后可以发现,本题的实质就是求 中t的最小值.这样一来,我们可以直接使用高精度算法来枚举t的最小值.但高精度算法却不能处理任何细胞都不满足要求的情况.故而,我们需要进行简单的数学分析.

首先分析样例:

样例1

样例2

2

3

1

1

列成表格后可以得到:

列成表格后可以得到:

2

3

5

3

1

1

1

1

2

1

通过观察得知,如果i细胞可以满足情况时,那么 有的质因数, 也一定有.反之,若 有的质因数,没有,则i细胞不能满足情况.而 的充要条件就是 中质因数的次数大于等于 中相同的质因数的次数.至此,题意分析完毕.

接下来,我简单的说一下算法的实现过程:

(1) 构造一个1..30000的质数表,来分解质因数.

(2) 注意 的特殊情况,此时任何 都能整除 ,故而直接输出0.

(3) 分解 ,建立一个m数组储存分解结果.

(4) 分解 ,然后递增t,直到 .这里有个优化,其实分解 时只需处理 中有的质因数,同样,枚举t的时候也只需处理 中有的质因数.此外,还需要设置一个变量处理 中的质因数>30000的情况,一种较为简单的方法是对比每次 的值,连续两次相等则退出.

(5) 输出最终结果.

【程序】

type

prime=array[1..3250] of word;

var

n,m1,m2,t,min,time,last,i,j:longint;

//t:30000以内的质数个数

//min:最短时间

//last:监视当前s[i]值,防止死循环

si:array[1..10000] of prime; //si[i]的质因数个数

s:array [1..10000] of longint;

p:array [1..3250] of 1..30000;//30000以内的质数表

m:prime;//m1^m2的质因数个数

flag:boolean;

function ok(x:integer):boolean;//判断s[x]与m1^m2是否含有相同质因数

begin

ok:=true;

for j:=1 to t do

if (m[j]<>0) and (si[x][j]=0) then exit(false);

end;

function ok(x,y:integer):boolean;//判断s[x]^y是否整除m1^m2

begin

ok:=true;

for j:=1 to t do

if (m[j]<>0) and (si[x][j]*y

end;

begin

fillchar(m,sizeof(m),0);

fillchar(si,sizeof(si),0);

readln(n);readln(m1,m2);

for i:=1 to n do read(s[i]);

p:=2;p:=3;t:=2;//用试除法构造30000以内质数表

for i:=4 to 30000 do

begin

flag:=true;

for j:=2 to trunc(sqrt(i))+1 do

if i mod j = 0 then

begin flag:=false;break;end;

if flag then

begin

inc(t);

p[t]:=i;

end;

end;

if m1=1 then //处理m1为1的特殊情况

begin

writeln(0);

halt;

end;

while m1<>1 do //分解m1^m2

for i:=1 to t do

if m1 mod p[i] = 0 then

begin

inc(m[i]);

m1:=m1 div p[i];

end;

for i:=1 to t do m[i]:=m[i]*m2;

flag:=false;min:=65535;

for i:=1 to n do

begin

time:=1;last:=0;

if s[i]=1 then continue;

while s[i]<>1 do //分解si[i]

begin

for j:=1 to t do

if (m[j] <> 0) and (s[i] mod p[j] = 0) then

begin

inc (si[i][j]);

s[i]:=s[i] div p[j];

end;

if last=s[i] then break;

last:=s[i];

end;

if ok(i) then //判断是否可以整除

begin

flag:=true;

while not ok(i,time) do inc(time);//递增time,直到整除为止

if time

end;

end;

if flag then writeln(min) else writeln(-1);

end.