JZOJ 1460.无题noname

Description

给定一个N,求出所有1到N之间的x,使得x^2=1(mod N)

Sample Input

7

Sample Output

1
6

Hint 

30%的数据N<=20000
100%的数据N<=2000000000

Solution(非正解,但不是水法)

Prepare

这题的答案是一步一步推来的。
由题得,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。
听说这样可以快这么几百毫秒,所以我就打了。

Code

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.

Special

其实我这个代码还是不够优美,有些地方有瑕疵,所以请各位大神雅正,呵呵。
——2016.2.17

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值