本来以为用一些奇妙的枚举顺序可以直接卡过去,然后弃疗。。
由题意可得 x^2 = 1 (mod n) ==> x^2 = k*n+1 ==> (x+1)(x-1) = k*n ==> n | (x+1)(x-1)
然后枚举n的约数。设n=a*b (a<b),若枚举a,就可求出b。然后令 a | (x+1),b | (x-1)。枚举可以被b整除的数(因为b>a),再判断它+2是否能被a整除。反过来再判断一次。如果(x+1)和(x-1)分别获得a、b中的因子,那么一定也会被其他情况枚举到,即做到了不重不漏。
代码中也有很多小坑。。
// BZOJ 1406
#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define dep(i,a,b) for (int i=a; i>=b; i--)
#define read(x) scanf("%d", &x)
#define fill(a,x) memset(a, x, sizeof(a))
int n;
set<int> S;
int main()
{
read(n);
int s=0;
for (int i=1; i*i<=n; i++) if (!(n%i)) {
int a=i, b=n/a;
rep(j,0,n/b) { // 注意从0开始
int x=j*b+1;
if (x<=n && !((x+1)%a)) S.insert(x); // 注意判断 0<=x<=n
x=j*b-1;
if (x>=0 && !((x-1)%a)) S.insert(x);
}
}
set<int>::iterator p;
if (!S.size()) puts("None");
else for (p=S.begin(); p!=S.end(); p++) printf("%d\n", *p); // 注意用指针输出
return 0;
}