[AHOI2007]密码箱

[AHOI2007]密码箱


\(n=1\)时无解,\(x=0\)时不成立。


暴力:\(O(n)\)

\(1\)~\(n\)扫一遍。


扩展欧几里得

发现一下式子:\(x^2≡1(\mod n)\)

移项得:\(x^2+k*n=1\)

于是运用扩展欧几里得求得一组解,进行判断即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#define all(x) x.begin(),x.end()
using namespace std;

typedef long long LL;

vector <LL> ans;
LL n;
void exgcd(LL a, LL b, LL &x, LL &y)
{
	if(!b)
	{
		x = 1, y = 0;	
		return;
	}	
	exgcd(b, a % b, y, x);
	y -= (a / b) * x;
	return;
}

int main()
{
	scanf("%lld", &n);
	if(n == 1)
	{
		puts("None");
		return 0;
	}
	LL res, y;
	exgcd(1, n, res, y);
	LL tmp = res;
	ans.clear();
	while(tmp < n * n)
	{
		if((LL)sqrt(tmp) * sqrt(tmp) == tmp) ans.push_back(sqrt(tmp));
		tmp += n;
	}
	tmp = res;
	while(tmp > 0)
	{
		tmp -= n;
		if((LL)sqrt(tmp) * sqrt(tmp) == tmp) ans.push_back(sqrt(tmp));
	}
	sort(all(ans));
	for(int i = 0; i < ans.size(); ++ i) printf("%d\n", ans[i]);
	return 0;
} 

扫描*枚举

由上述思路:\(x^2+k*n=1\)可以换一个角度思考。

=>\((x+1)(x-1)=k*n\)

这个式子提示我们,\(n\)\(x+1\)\(x-1\)的因数,不妨设\(n=a*b\),需要满足:\(x-1|a\)\(x+1|b\)\(x-1|b\)\(x+1|a\)

那么枚举\(n\)的因数,选最大的往上枚举\(x\),最后判断。

另外,不开long long可能有意想不到的错误。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

typedef long long LL;

LL n, cnt = 0, ans[100000];

int main()
{
	scanf("%lld", &n);	
	if(n == 1)
	{
		puts("None");
		return 0;
	}
	ans[cnt ++] = 1;
	LL MAXN = sqrt(n), b;
	//Time Complexity: O(n^{0.5}ln(n)) 
	for(LL a = 1; a <= MAXN; ++ a)	
	{
		if(n % a == 0)
		{
			b = n / a;//枚举 n 的两个因数 
			for(LL x = b + 1; x <= n; x += b) //枚举x-1|a&x+1|b的情况 
			{
				if((x + 1) % a == 0) ans[cnt ++] = x; 
			}
			if(a == b) break;   
			for(LL x = b - 1; x <= n; x += b) //枚举x-1|b&x+1|a的情况 
			{
				if((x - 1) % a == 0) ans[cnt ++] = x;
			}
		}
	} 
	sort(ans, ans + cnt);
	cnt = unique(ans, ans + cnt) - ans; 
	for(int i = 0; i < cnt; ++ i) printf("%lld\n", ans[i]);
	return 0;
}
posted @ 2020-12-13 10:33  大秦帝国  阅读(76)  评论(0编辑  收藏  举报