1. 题目
数数
【问题描述】
给定n,m,k都是小于等于10001的正整数,输出给定的n个数中,其m次幂能被k整除的数的个数。
【输入格式】
有两行组成,第一行是三个整数n,m,k
第二行是n个正整数 都不超过10001
【输出格式】
输出满足条件的数的个数
【样例输入】count.in
3 2 50
9 10 11
【样例输出】count.out
1
2. 题目实质
判断给定数的 m 次幂能否被 k 整除。
3. 算法
第一种思路是,将这个数的 m 次幂求出来,然后直接判断。方法是快速幂。但是,理论上讲,这么做是要用到高精的。不过可以每计算一次就 mod 一次或者是约分一次,这样可以不用高精。
然后,第二种思路。
当一个数可以整除 k 时,它的每一个质因子的指数都应大于等于 k 的对应质因子的指数。(这么白痴的定理我就不用证明了吧?)
所以,我们可以先对 k 进行分解质因数,将它的每一个质因子的指数存起来,然后再将给定的那个数分解质因数,将它的每一个质因子的指数乘以 m 。(这样就相当于对它的 m 次幂分解质因数了)然后,判断 k 有没有比这个数的 m 次幂多出的质因子,或是某个质因子的指数比这个数的 m 次幂更高。
然后,然后就是这样。
4. 注意事项
快速幂要及时 mod 或是约分。
分解质因数要预处理出质数表,然后要将 k 和指定的这个数的质因子都判断一下,不要只判断这个数的质因子,不然会判断不全。
5. 代码
快速幂(艾 FHAI)
var
x,ans,i,n,m,k:longint;
procedure check(r,m,k:longint);
var
i,t:longint;
begin
t:=r;dec(m);
while m<>0 do
begin
if m mod 2<>0 then t:=(t*r)mod k;
m:=m div 2;
t:=(t*t)mod k;
end;
{t:=1;
for i:=1to m do
t:=(t*r)mod k; }
if t=0 then inc(ans);
end;
begin
assign(input,'count.in');reset(input);
assign(output,'count.out');rewrite(output);
readln(n,m,k);
for i:=1 to n do
begin
read(x);
check(x,m,k);
end;
writeln(ans);
close(input);close(output);
end.
分解质因数 (SueMiller)
var v:array[0..20000]of boolean;
f:array[0..20000]of longint;
g1,g2:array[0..20000]of longint;
i,j,nn,nk:longint;
n,m,k:longint;
p,ans:longint;
flag:boolean;
begin
assign(input,'count.in');reset(input);
assign(output,'count.out');rewrite(output);
fillchar(v,sizeof(v),false);
for i:=2 to 20000 do
if not v[i] then
begin
j:=i;
while j+i<20000 do
begin
j:=j+i;
v[j]:=true;
end;
end;
readln(n,m,k);
fillchar(f,sizeof(f),0);
fillchar(g1,sizeof(g1),0);
nn:=0;
nk:=0;
for i:=2 to 20000 do
if not v[i] then begin
inc(nn);
f[nn]:=i;
while k mod i=0 do
begin
k:=k div i;
inc(g1[nn]);
end;
if (k=1) and (nk=0) then nk:=nn;
end;
if k<>1 then
begin
writeln(0);
close(input);close(output);
halt;
end;
ans:=0;
for i:=1 to n do
begin
read(p);
flag:=false;
j:=0;
fillchar(g2,sizeof(g2),0);
if (p=1) and (k<>1) then continue;
if (p=0) and (k<>0) then continue;
repeat
inc(j);
while p mod f[j]=0 do
begin
p:=p div f[j];
inc(g2[j]);
end;
g2[j]:=g2[j]*m-g1[j];
// writeln('&&& ',p,' ',g2[j]);
// g1[j]:=0;
if g2[j]<0 then begin flag:=true; break end;
// writeln('** ',g2[j],' ',g1[j],' ',j) ;
until j>=nk;
// for j:=1 to nk do
// if g1[j]<>0 then continue;
if not flag then inc(ans);
end;
writeln(ans);
close(input);close(output);
end.