BZOJ 1406 - 伪数论
本来以为用一些奇妙的枚举顺序可以直接卡过去,然后弃疗。。
由题意可得 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; }