【带模的除法】poi2008 per

这道题的难点在于带模的除法,可恶的是模还不是质数,更可恶的是还没办法约分。。

 

看了标程才知道原来还可以这样做:

把取模的数进行分解质因数,对于你要乘或者要除以某一个数的时候,将这个数和模的gcd额外处理(其实直接把质因数的几次幂记下来就可以了),对于不是gcd的部分直接乘法逆元即可。

 

我是参考的标程的写法(ps:标程跑得非常慢),加略微的改进,感觉我应该不会写丑啊。。。但是交到h8oj上面去的时候果断被虐了。。估计是还有更优美的算法,那位路过的同学知道的告诉我哈。。

 

program per;{$inline+} var a,b,c:array[0..300000] of longint; d:array[0..10,-100..43] of int64; x,y,z,p:array[0..10] of int64; n,i,j,zt,ans,phm:longint; lt,mo,ch,pre,tmp:int64; function get:int64;inline;var i:longint; begin get:=lt;for i:=1 to zt do get:=get*p[i] mod mo end; function fmul(a:int64;b:longint):int64;inline; begin if (b=0)or(a=1) then exit(1); fmul:=sqr(fmul(a,b>>1))mod mo; if odd(b) then fmul:=fmul*a mod mo; end; function phi(x:longint):longint;inline;var i,k:longint; begin i:=1;phi:=1; while i*i<=x do begin inc(i);k:=1; while x mod i=0 do begin x:=x div i; k:=k*i; end; phi:=phi*(k-k div i); end; if x<>1 then phi:=phi*(x-1); end; procedure calc(a,b:int64);inline;var i:longint; begin for i:=1 to zt do while a mod x[i]=0 do begin a:=a div x[i]; inc(y[i],b); if b=1 then p[i]:=p[i]*x[i] mod mo else p[i]:=p[i]*z[i] mod mo; if y[i]<43 then p[i]:=d[i,y[i]]; end; if b=1 then lt:=lt*(a mod mo)mod mo else lt:=lt*fmul(a,phm) mod mo; end; begin readln(n,mo); tmp:=mo;lt:=1; for i:=1 to n do read(a[i]); for i:=2 to mo do if i*i>tmp then break else if tmp mod i=0 then begin inc(zt);x[zt]:=i; while tmp mod i=0 do tmp:=tmp div i; end; if tmp<>1 then begin inc(zt);x[zt]:=tmp; end; for i:=1 to zt do p[i]:=1; for i:=1 to zt do d[i,0]:=1; for i:=1 to zt do for j:=1 to 43 do d[i,j]:=d[i,j-1]*x[i] mod mo; for i:=1 to zt do begin tmp:=mo; while tmp mod x[i]=0 do tmp:=tmp div x[i]; z[i]:=fmul(x[i],phi(tmp)-1); end; phm:=phi(mo)-1; ans:=1;pre:=1; for i:=n downto 1 do begin inc(c[a[i]]); tmp:=0;j:=a[i]-1; while j>0 do begin inc(tmp,b[j]); dec(j,j and -j); end; j:=a[i]; while j<300001 do begin inc(b[j]); inc(j,j and -j); end; if n=i then ch:=1 else ch:=n-i; if tmp<>0 then ch:=ch*tmp; calc(ch,1); if pre=0 then calc(c[a[i]],-1) else calc(c[a[i]]*pre,-1); if tmp<>0 then ans:=(ans+get)mod mo; pre:=tmp; end; writeln(ans); end.  

 

你可能感兴趣的:(c,算法,function,div)