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

传送门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]);
}

你可能感兴趣的:(【BZOJ1406】【codevs2478】密码箱,数论练习)