2、MMT数
FF博士最近在研究MMT数(莫明堂数-_-)。
如果对于一个数n,存在gcd(n,x)<>1并且n mod x<>0 那么x叫做n的MMT数
显然这样的数可以有无限个。
FF博士现在想知道在所有小于n的正整数里面有多少个n的MMT数
输入样例:
10
输出样例:
3
样例解释: 3个数分别是 4 6 8
gcd(n,x)的意思是求n和x的最大公约数
对于50%的数据 n<=1000000
对于100%的数据n<=maxlongint
【考察点】
数论,准确地说,欧拉函数
【思路】
反正我考试的时候是没有办法的……朴素了50分。
看完解题报告后,我还是推不出那个破公式,于是只能直接用结论了……
(以下复制)
这道题定位为纯数论题..因为实在不知道该怎么藏算法。
假设一个数n分解质因数以后为p1^k1*p2^k2*p3^k3……(p为质因数)
那么他的因数个数为a=(k1+1)*(k2+1)*(k3+1)…
在所有比n小的数里与n互质的数的个数其实就是欧拉函数,b=n*[1-(1/p1)]*[1-(1/p2)]*[1-(1/p3)]
这两种数里都含有1,所以n的MMT数为n-(a+b-1)。
纯模拟也可以有50分。
至于怎么分解质因数就不用说了吧,算素数或者打素数表都可以。
>_<不会欧拉函数的童鞋就当学了个新知识吧,也许以后会有用哦。
【提交情况】
考试TLE50,下来搞了很久之后AC
【经验及收货】
素数这种东西果然还是打表让人舒服些……
【吐槽】
该死的数论……给各种数学牛跪了……给能手动推出欧拉函数的跪了……
ACCode:
Program mmt;
Var
a,b,c:array[0..10000]of longint;
f:array[0..10000]of boolean;
n:longint;
Procedure terminate;
begin
close(input);
close(output);
halt;
end;
Procedure init;
begin
assign(input,'mmt.in');
assign(output,'mmt.out');
reset(input);
rewrite(output);
readln(n);
end;
Procedure main;
var
i,j,k,m,x,y,t,tot,z,h,tt:longint;
s:real;
flag:boolean;
begin
m:=n;
h:=0;
t:=0;
for j:=2 to trunc(sqrt(maxlongint)) do
begin
flag:=true;
for i:=2 to trunc(sqrt(j)) do
if j mod i=0 then
begin
flag:=false;
break;
end;
if flag then begin inc(t);a[t]:=j;end;
end;
for i:=1 to t do
while n mod a[i]=0 do
begin
inc(c[i]);
n:=n div a[i];
end;
if n<>1 then
begin
a[t+1]:=n;
c[t+1]:=1;
inc(t);
end;
tt:=1;
n:=m;
for i:=1 to t do tt:=tt*(c[i]+1);
s:=m;
for i:=1 to t do
begin
if c[i]=0 then continue;
s:=s-s/a[i];
end;
s:=round(s);
writeln(n-(tt+s-1):0:0);
end;
Begin
init;
main;
terminate;
End.