【BZOJ1406】【codevs2478】密码箱,数论练习

来源:互联网 发布:建筑方案设计软件 编辑:程序博客网 时间:2024/05/20 19:30

传送门1
传送门2
写在前面:纯洁的污,还要恍然大污
思路:
(感觉数论一段时间不做就找不到感觉了呢)
题意就是求x21(mod n)在[0,n]上所有的整数解
方程可化为(x1)(x+1)0(mod n)
n|(x1)(x+1)
n=ab,其中a,b就是n的正整数因子。则对于一个可行的x来说,一定至少有1对(a,b)满足
a|(x1),b|(x+1)a|(x+1),b|(x1)
反过来说也是成立的
(至于证明,我们可以n与(x+1)(x-1)质因数分解,则{n的质因子}⊆{x+1的质因子}∪{x-1的质因子},而n的因子是(1,n)或质因子乘起来的,所以一定能找出一对符合条件的(a,b))
这样一来我们就比较容易地做到两件事,一是说明当n=1时无解(不可能有一个自然数是0的因子),否则一定有解(当x=n-1时,令a,b为1,n即可),二是O(n)筛出n的因子,然后通过枚举每个因子的倍数p,然后判断p是否能为x-1或x+1,最后得出方程的解
注意:
1.可能会有重复解,所以用map判重
2.选取大于√n的因子做判断,不然会T
3.x=1是任何n的解(n>1)
代码:

#include<bits/stdc++.h>#include<set>using namespace std;int n;int a[50000],ans[1000000];map<int,bool>mp;main(){    scanf("%d",&n);    if (n==1) printf("None"),exit(0);    ans[++ans[0]]=1;    for (int i=1;i<=sqrt(n);i++)    if (n%i==0) a[++a[0]]=n/i;      for (int i=1;i<=a[0];i++)    for (int j=a[i];j<=n;j+=a[i])    {        if ((j+2)%(n/a[i])==0&&j+1<=n&&!mp[j+1])        mp[j+1]=1,        ans[++ans[0]]=j+1;        if ((j-2)%(n/a[i])==0&&j-1>=0&&!mp[j-1])        mp[j-1]=1,        ans[++ans[0]]=j-1;    }    sort(ans+1,ans+ans[0]+1);    for (int i=1;i<=ans[0];i++) printf("%d\n",ans[i]);}
0 0