给定一个N,求出所有1到N之间的x,使得x^2=1(mod N)
7
1
6
30%的数据N<=20000
100%的数据N<=2000000000
这题的答案是一步一步推来的。
由题得,x^2-yn=1(y为正整数)
x^2-1=yn
(x^2-1)/n=y (已知n,y为正整数,所以(x^2-1)也为整数)
(x+1)(x-1)/n=y
首先我们从n下手
我们将n分解质因数,令n=p1^k1* p2^k2 * …*pn^kn
我们枚举k1,k2…kn的值q1(0≤q1≤k1),q2(0≤q2≤k2),..qn(0≤qn≤kn),令a1=p1^q1* p2^q2* …*pn^qn.
则a2=n/a1(a1|x+1,a2|x-1)
因为n|(x+1)(x-1),所以令
①x+1=m1a1,
②x-1=m2a2
则有m1=(m2a2+2)/a1,m2=(m1a1-2)/a2
我们用i枚举m1,m2.将i带入m1,m2.
则有
m1=(ia2+2)/a1, 此时x=ia2+1
m2=(ia1-2)/a2 此时x=ia1-1
只要这时求得的m1或m2为整数,则将x记入答案。(记得用ans数组将答案存起来)
在排序之前加上元素1,ans数组从小到大排序输出。
很多人只是将p1和k1存起来,而我每一个质因数还存了p1^1,p1^2,…p1^k。
听说这样可以快这么几百毫秒,所以我就打了。
var p:array[0..10,0..31] of int64;
ans:array[0..10000] of int64;
i,j,k,tot,da,q:longint;
a1,a2,n:int64;
procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=ans[(l+r)div 2];
repeat
while ans[i]<mid do inc(i);
while ans[j]>mid do dec(j);
if i<=j then
begin
ans[0]:=ans[i];
ans[i]:=ans[j];
ans[j]:=ans[0];
inc(i);dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure dg(k:longint;a1:int64);
var i,j:longint;
begin
if k>tot then
begin
a2:=n div a1;
for i:=1 to n do
begin
if (a1*i-1>n)or(a2*i+1>n) then break;
if (a2*i+2)mod a1=0 then
begin
inc(da);
ans[da]:=a2*i+1;
end;
if (a1*i-2)mod a2=0 then
begin
inc(da);
ans[da]:=a1*i-1;
end;
end;
exit;
end;
for i:=0 to p[k,0] do//我这里就直接存了上述p的乘方
if i=0 then dg(k+1,a1) else dg(k+1,a1*p[k,i]);
end;
begin
readln(n);
k:=n;
i:=1;//优化
while (i*i<=n)and(k>1) do
begin
inc(i);
if k mod i=0 then
begin
inc(tot);
p[tot,0]:=1;
q:=0;
while k mod i=0 do
begin
inc(q);
k:=k div i;
p[tot,q]:=p[tot,q-1]*i;
end;
p[tot,0]:=q;
end;
end;
if k>0 then
begin
inc(tot);
p[tot,0]:=1; //不要忘记这个部分。特别是当n为质数的时候。
p[tot,1]:=k;
end;
dg(1,1);
inc(da);
ans[da]:=1;
qsort(1,da);
i:=0;
while i<da do
begin
inc(i);
while ans[i]=ans[i-1] do inc(i);
if i>da then break;
writeln(ans[i]);
end;
end.
其实我这个代码还是不够优美,有些地方有瑕疵,所以请各位大神雅正,呵呵。
——2016.2.17 By Wzy