Description
由于BZOJ的水题已经被Lcomyn大爷刷完了,所以机房的蒟蒻们决定再出一道水题给lcomyn刷。
正巧蒟蒻们最近做了AHOI2007密码箱,觉得这题实在太水了。稍微加强一下下依然还是很水的,所以决定把数据范围开大一点送给Lcomyn切。
求方程x^2=1(mod n)的解,x为小于n的非负整数。
Input
一行一个数n。
Output
如果方程无解输出None,否则就按从小到大的顺序输出所有解,两个数之间用空格隔开,行末无多余空格。
Sample Input
5
Sample Output
1 4
HINT
1<=n<=10^18
Source
By TA
题目跟原题一样数据范围扩大了
是为了让用Pollard_Rho做因数分解用Miller_Rabin判素数所以开打了范围
特地去学了一遍
跟着Lcomyn大爷学了姿势\
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define MAXN 320010
#define Abs(x) ((x)>0?(x):-(x))
#define RAND (LL)((LL)rand()*(LL)rand())%p
using namespace std;
const int TEST_NUM=20;
LL n,x,y;
LL fac[64],top,b[64],ret[64];
LL ans[MAXN],num;
LL Mult(LL x,LL n,LL P)
{
LL ret=0;
for (LL i=n;i;i>>=1,x=(x<<1)%P)
if (i&1) ret+=x%P,ret%=P;ret=(ret+P)%P;
return (ret+P)%P;
}
LL Pow(LL x,LL n,LL P)
{
LL ret=1;
for (LL i=n;i;i>>=1,x=Mult(x,x,P))
if (i&1) ret=Mult(ret,x,P);
return (ret+P)%P;
}
bool check(LL a,LL n,LL x,LL t)
{
LL ret=Pow(a,x,n),last=ret;
for (LL i=1;i<=t;i++)
{
ret=Mult(ret,ret,n);
if (ret==1&&last!=1&&last!=n-1) return 0;
last=ret;
}
return (ret==1);
}
bool Miller_rabin(LL n)
{
LL x=n-1,RANDNUM,t=0;
if (n<=2) return (n==2);
if (!(n&1)) return 0;
if (!(x&1)) x>>=1,t++;
for (int i=1;i<=TEST_NUM;i++)
{
RANDNUM=rand()%(n-2)+2;
if (!check(RANDNUM,n,x,t)) return 0;
}
return 1;
}
LL gcd(LL a,LL b)
{
return !b?a:gcd(b,a%b);
}
LL Pollard_rho(LL p)
{
LL i=1,k=2,x,y,c,ret;
c=RAND;y=x=RAND;
while (1)
{
i++;x=(Mult(x,x,p)+c)%p;ret=gcd(Abs(y-x),p);
if (ret!=1) return ret;
if (i==k) y=x,k<<=1;
}
}
void get_fac(LL n)
{
LL i,minn;
bool flag=Miller_rabin(n),b;
if (flag)
{
b=0;
for (i=1;i<=top;i++)
if (fac[i]%n==0) fac[i]*=n,b=1;
if (!b) fac[++top]=n;
}
else
{
// cout<<n<<' ';
minn=Pollard_rho(n);//cout<<minn<<endl;
while (minn==n) minn=Pollard_rho(n);//,cout<<minn<<endl;
get_fac(minn);get_fac(n/minn);
}
}
void ex_gcd(LL a,LL b,LL p)
{
LL tmp;
if (a%b==0) x=0,y=1;
else ex_gcd(b,a%b,p),tmp=x%p,x=y%p,y=(tmp-Mult(a/b,y,p)+p)%p;
}
void make_ret()
{
for (LL tmp,now,i=1;i<=top;i++) now=n/fac[i],now%=fac[i],ex_gcd(now,fac[i],fac[i]),x=(x%fac[i]+fac[i])%fac[i],tmp=n/fac[i],ret[i]=Mult(x,tmp,n);
}
void solve()
{
LL new_ans=0;
for (LL i=1;i<=top;i++) x=Mult(ret[i],b[i],n),new_ans=(new_ans+x)%n;
ans[++num]=new_ans;
}
void work(LL i)
{
if (i==top+1) {solve();return;}
if (fac[i]==2) b[i]=1,work(i+1);
else
{
b[i]=fac[i]-1;work(i+1);
b[i]=1;work(i+1);
if (!(fac[i]&1)&&fac[i]>4) b[i]=fac[i]/2+1,work(i+1),b[i]=fac[i]/2-1,work(i+1);
}
}
int main()
{
cin>>n;
if (n==1) {puts("None");return 0;}
get_fac(n);make_ret();work(1);
sort(ans+1,ans+num+1);int size=unique(ans+1,ans+num+1)-ans-1;
for (int i=1;i<size;i++) printf("%lld ",ans[i]);printf("%lld\n",ans[size]);
}