【BZOJ1406】密码箱
1406: [AHOI2007]密码箱
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1406 Solved: 832
[Submit][Status][Discuss]
Description
在一次偶然的情况下,小可可得到了一个密码箱,听说里面藏着一份古代流传下来的藏宝图,只要能破解密码就能打开箱子,而箱子背面刻着的古代图标,就是对密码的提示。经过艰苦的破译,小可可发现,这些图标表示一个数以及这个数与密码的关系。假设这个数是n,密码为x,那么可以得到如下表述: 密码x大于等于0,且小于n,而x的平方除以n,得到的余数为1。 小可可知道满足上述条件的x可能不止一个,所以一定要把所有满足条件的x计算出来,密码肯定就在其中。计算的过程是很艰苦的,你能否编写一个程序来帮助小可可呢?(题中x,n均为正整数)
Input
输入文件只有一行,且只有一个数字n(1<=n<=2,000,000,000)。
Output
你的程序需要找到所有满足前面所描述条件的x,如果不存在这样的x,你的程序只需输出一行“None”(引号不输出),否则请按照从小到大的顺序输出这些x,每行一个数。
Sample Input
12
Sample Output
1
5
7
11
5
7
11
HINT
枚举因子 复杂度很玄学
具体来说 我们将原式整理成$x^{2} \equiv 1 (mod n)$
那么我们发现$x^{2}-1=kn$
那么我们枚举因子$a$ 令$b$=$\frac{n}{a}$
然后我们枚举$x \in \lbrace x-1=kb,x \leq n \rbrace $ 和 $x \in \{ x+1=kb,x \leq n \} $
从而验证$x+1 \equiv 0 (mod \quad a) $ 和 $x-1 \equiv 0 (mod \quad a) $
如果成立并且还不在set内就加入
复杂度$ \mathcal{O} (\sqrt{n} * \sqrt{n} * \log{ \sqrt{n} })$
但是sqrt(n)*sqrt(n)这里有个很小的常数 能让他变快特别多
/*To The End Of The Galaxy*/ #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<iomanip> #include<stack> #include<map> #include<set> #include<cmath> #include<complex> #define debug(x) cerr<<#x<<"="<<x<<endl #define INF 0x7f7f7f7f #define llINF 0x7fffffffffffll using namespace std; typedef pair<int,int> pii; typedef long long ll; inline int init() { int now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } inline long long llinit() { long long now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } set<ll> st; int main() { ll n,a,b; n=llinit(); for(int i=1;i*i<=n;i++) { if(n%i==0) { a=i; b=n/i; for(ll x=1;x<=n;x+=b) { if((x+1)%a==0) { st.insert(x); } } for(ll x=b-1;x<=n;x+=b) { if((x-1)%a==0) { st.insert(x); } } } } set<ll>::iterator it; for(it=st.begin();it!=st.end();it++) { printf("%lld\n",*it); } return 0; }