P4296 [AHOI2007]密码箱
密码x大于等于0,且小于n,而x的平方除以n,得到的余数为1。
求这个密码,$1<=n<=2,000,000,000$
暴力枚举,数据有点儿水$O(nlogn)$,显然过不了$n<=10^9$
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #define LL long long using namespace std; LL n; bool flg=false; int main() { scanf("%lld",&n); for(int i=0;;i++){ LL x=i*n+1,p=sqrt(x); if(p>n) break; if(p*p==x){ flg=true; printf("%lld ",p); } } if(!flg) return puts("None"),0; return 0; }
正解:
题目要求$x^xmod n =1$,也就是求$n|(x^2-1^2)$,即$n|(x-1) imes(x+1)$,既然如此,考虑将$n$拆开,就有$n=a imes b$ $a|(x+1),b|(x-1)$或是$b|(x+1),a|(x-1)$
不妨设$a<b$,枚举$a$,同时枚举两种情况,优先队列+$STL$——$map$判重
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<map> #include<queue> #include<vector> #define LL long long using namespace std; LL n; bool flg=false; priority_queue<LL,vector<LL>,greater<LL> >Q; map<LL,bool>M; int main() { scanf("%lld",&n); int p=sqrt(n); for(int i=1;i<=p;i++){ if(n%i==0){ int b=n/i; for(int x=1;x<=n;x+=b)//b|x-1 if((x+1)%i==0&&!M[x]) Q.push(x),M[x]=1; for(int x=b-1;x<=n;x+=b)//b|x+1 if((x-1)%i==0&&!M[x]) Q.push(x),M[x]=1; } } while(!Q.empty()){ printf("%lld ",Q.top()); Q.pop(); } return 0; }
或是$set$去重
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<map> #include<queue> #include<vector> #include<set> #define LL long long using namespace std; LL n; bool flg=false; set<LL>S; int main() { scanf("%lld",&n); int p=sqrt(n); for(int i=1;i<=p;i++){ if(n%i==0){ int b=n/i; for(int x=1;x<=n;x+=b)//b|x-1 if((x+1)%i==0) S.insert(x); for(int x=b-1;x<=n;x+=b)//b|x+1 if((x-1)%i==0) S.insert(x); } } while(!S.empty()){ printf("%lld ",*S.begin()); S.erase(S.begin()); } return 0; }
貌似没有$None$的情况,即数据里不存在$n=1$