【洛谷P4296】密码箱

题目

题目链接:https://www.luogu.com.cn/problem/P4296
在一次偶然的情况下,小可可得到了一个密码箱,听说里面藏着一份古代流传下来的藏宝图,只要能破解密码就能打开箱子,而箱子背面刻着的古代图标,就是对密码的提示。

经过艰苦的破译,小可可发现,这些图标表示一个数以及这个数与密码的关系。假设这个数是 \(n\),密码为 \(x\),那么可以得到如下表述: 密码 \(x\) 大于等于 \(0\),且小于 \(n\),而 \(x\) 的平方除以 \(n\),得到的余数为 \(1\)。 小可可知道满足上述条件的 \(x\) 可能不止一个,所以一定要把所有满足条件的 \(x\) 计算出来,密码肯定就在其中。计算的过程是很艰苦的,你能否编写一个程序来帮助小可可呢?

思路

\(x^2\equiv 1\pmod n\) 等价于 \((x-1)(x+1)\bmod n=0\)
\(n=ab\)\(x\) 是解当且仅当存在 \(a,b\) 满足 \(a|(x-1)\)\(b|(x+1)\)
\(a\leq b\),枚举 \(a\),可以计算出 \(b\),对于每一个 \(b\) 的倍数我们都令他为 \(x+1\),那么我们继续枚举 \(b\) 的倍数,只需要判断 \(x-1\) 是不是 \(a\) 的倍数即可。
时间复杂度 \(O(n)\),当然这是十分轻松的上界。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n;
set<int> s;

int main()
{
	scanf("%d",&n);
	if (n==1) return printf("None"),0;
	for (int i=1;i*i<=n;i++)
		if (n%i==0)
		{
			int k=n/i;
			for (ll j=k;j-1<=n;j+=k)
				if ((j-2)%i==0) s.insert(j-1);
			for (ll j=k;j+1<=n;j+=k)
				if ((j+2)%i==0) s.insert(j+1);
		}
	s.insert(1);
	for (set<int>::iterator it=s.begin();it!=s.end();it++)
		printf("%d\n",*it);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/13819663.html