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;
}


posted @ 2015-12-14 20:07  Armeria  阅读(151)  评论(0编辑  收藏  举报