莫比乌斯反演就是说得通俗点就是把元素的和通过加上系数还原成原来的元素,其中最主要的就是确定系数,即莫比乌斯函数(广义)。
在信息学中,使用数论中的莫比乌斯反演最好是用线性筛法O(n)和分块求和O(sqrt(n)).
题目:spoj7001(入门1)
program spoj7001;
var
N:longint;
tp:array[1..1000000] of boolean;
prime,s,u:array[0..1000000] of int64;
pn,i,j,t:longint;
ans,now:int64;
procedure pre;
var
i,j:longint;
begin
fillchar(tp,sizeof(tp),0);
for i:=2 to 1000000 do begin
if not tp[i] then begin
inc(pn);prime[pn]:=i;u[i]:=-1;
end;
for j:=1 to pn do begin
if i*prime[j]>1000000 then break;
tp[prime[j]*i]:=true;
if i mod prime[j]=0 then begin
u[i*prime[j]]:=0;break;
end;
u[i*prime[j]]:=-u[i];
end;
end;
u[1]:=1;s[0]:=0;
for i:=1 to 1000000 do s[i]:=s[i-1]+u[i];
end;
begin
pre;
readln(T);
for j:=1 to T do begin
readln(N);
i:=1;ans:=0;
while i<=N do begin
now:=N div (N div i);
ans:=ans+((N div now+1)*(N div now+1)*(N div now+1)-1)*(s[now]-s[i-1]);
i:=now+1;
end;
writeln(ans);
end;
end.
ZOJ3435(入门2)
program zoj3435;
var
u,sum:array[0..1000000] of int64;
prime:array[0..1000000] of int64;
tp:array[0..1000000] of boolean;
ans,L,W,H,now,i:int64;
pn:Longint;
procedure getprime;
var
j,i:longint;
flag:boolean;
begin
fillchar(tp,sizeof(tp),0);
pn:=0;u[1]:=1;
for i:=2 to 1000000 do begin
if not tp[i] then begin
inc(pn);prime[pn]:=i;u[i]:=-1;
end;
for j:=1 to pn do begin
if prime[j]*int64(i)>1000000 then break;
tp[prime[j]*i]:=true;
if i mod prime[j]=0 then begin
u[prime[j]*i]:=0;break;
end;
u[prime[j]*i]:=-u[i];
end;
end;
sum[1]:=1;
for i:=2 to 1000000 do sum[i]:=sum[i-1]+u[i];
end;
function max(a,b:longint):longint;begin if a>b then exit(a);exit(b);end;
function min(a,b:longint):longint;begin if a<b then exit(a);exit(b);end;
begin
getprime;
while not seekeof do begin
readln(L,W,H);
dec(L);dec(W);dec(H);
ans:=0;
i:=1;
sum[0]:=0;
while (i<=L) or (i<=W) or (i<=H) do begin
now:=maxlongint;
if i<=L then now:=min(now,L div (L div i));
if i<=W then now:=min(now,W div (W div i));
if i<=H then now:=min(now,H div (H div i));
ans:=ans+(sum[now]-sum[i-1])*((L div now+1)*(W div now+1)*(H div now+1)-1);
i:=now+1;
end;
writeln(ans);
end;
end.
spoj4491(精通)
这道题不能套模板,需要灵活将miu修改。(为了节约内存,miu直接用prime代替)
program spoj4491;
const
maxn=10000000;
var
sum:array[0..10000000] of int64;
cn1,cn2:array[0..10000000] of longint;
prime:array[0..10000000] of int64;
tprime:array[1..10000000] of boolean;
pn:longint;
n,i:longint;
x,y:int64;
procedure pre;
var
i,j:longint;
begin
fillchar(tprime,sizeof(tprime),0);
pn:=0;
for i:=2 to maxn do begin
if not tprime[i] then begin
inc(pn);prime[pn]:=i;
cn1[i]:=1;cn2[i]:=0;
end;
for j:=1 to pn do begin
if prime[j]>maxn div i then break;
tprime[prime[j]*i]:=true;
if i mod prime[j]=0 then begin
if i div prime[j] mod prime[j]=0 then begin
cn2[i*prime[j]]:=2;
cn1[i*prime[j]]:=cn1[i];
end
else begin
cn1[i*prime[j]]:=cn1[i];
cn2[i*prime[j]]:=cn2[i]+1;
end;
break;
end;
cn1[i*prime[j]]:=cn1[i]+1;
cn2[i*prime[j]]:=cn2[i];
end;
end;
prime[1]:=0;
for i:=2 to maxn do
if cn2[i]=1 then begin
prime[i]:=-(cn1[i] and 1)shl 1+1;
end
else if cn2[i]=0 then begin
prime[i]:=cn1[i]*((cn1[i] and 1) shl 1-1)
end
else prime[i]:=0;
for i:=1 to maxn do sum[i]:=sum[i-1]+prime[i];
end;
procedure work;
var
i,now,j:longint;
ans:int64;
function min(a,b:longint):longint;begin if a<b then exit(a);exit(b);end;
begin
ans:=0;
i:=1;
while (i<=x) or (i<=y) do begin
now:=maxlongint;
if i<=x then now:=min(now,x div (x div i));
if i<=y then now:=min(now,y div (y div i));
ans:=ans+(x div now)*(y div now)*(sum[now]-sum[i-1]);
i:=now+1;
end;
writeln(ans);
end;
begin
pre;
readln(n);
for i:=1 to n do begin
readln(x,y);
work;
end;
end.