[ AHOI2007 ] 密码箱
洛谷的数据超级水!不用任何优化的暴力枚举都能过!
正解需要一点数学推导:
\(\because x^2\ mod\ n=1\)
\(\therefore x^2-1=(x-1)(x+1)mod\ n=1\)
则必定存在\(a,b\)满足\(a|(x-1),b|(x+1)\)或\(b|(x-1),a|(x+1)\)
枚举每一个\(a\),对于每一个\(a\),枚举\(x\)
在枚举 x 的时候无需从 1 开始逐个枚举,可以直接从\(\sqrt{n}\)开始,因为任何小于 \(\sqrt{n}\) 的数字,其平方都小于 \(n\),一定不满足条件(1 除外)
但洛谷上评测时最后一个点超时。。。
另外,还可以只枚举\(x-1\)或\(x+1\)是\(b\)的倍数的 x ,这样每次只需要加 b ,可以减少枚举数
这种方法是可以AC的,但是当我想将上面的两种方法结合在一起时,却莫名其妙地WA了。。。为神马。。。
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
vector<int> ans;
int main()
{
int n;
cin>>n;
if(n==1)
{
printf("None");
return 0;
}
ans.push_back(1);
const int m=sqrt(n);
for(int a=1; a<=m; a++)
{
if(n%a) continue;//n 不能整除 a
int b=n/a;
for(int x=b-1; x<n; x+=b)
{
if((x-1)%a==0)
{
ans.push_back(x);
}
}
for(int x=1; x<n; x+=b)
{
if((x+1)%a==0)
{
ans.push_back(x);
}
}
}
sort(ans.begin(),ans.end());
for(int i=0,cnt=ans.size(); i<cnt; i++)
if(!i || ans[i]!=ans[i-1]) printf("%d\n",ans[i]);
return 0;
}