【题解】密码箱

题目描述

        在一次偶然的情况下,小可可得到了一个密码箱,听说里面藏着一份古代流传下来的藏宝图,只要能破解密码就能打开箱子,而箱子背面刻着的古代图标,就是对密码的提示。经过艰苦的破译,小可可发现,这些图标表示一个数以及这个数与密码的关系。假设这个数是n,密码为x,那么可以得到如下表述:

        密码x大于等于0,且小于n,而x的平方除以n,得到的余数为1。

        小可可知道满足上述条件的x可能不止一个,所以一定要把所有满足条件的x计算出来,密码肯定就在其中。计算的过程是很艰苦的,你能否编写一个程序来帮助小可可呢?(题中x,n均为正整数)

 

输入输出格式

输入格式

        一行,且只有一个数字n。(1≤n≤200000000)

 

输出格式

       你的程序需要找到所有满足前面所描述条件的x,如果不存在这样的x,你的程序只需输出一行“None”(引号不输出),否则请按照从小到大的顺序输出这些x,每行一个数。

 

输入输出样例

输入样例

12

输出样例

1

5

7

11

 

题解

         n很大,所以直接暴力枚举x会爆。我们可以从减少枚举x的次数出发。

         如题,x²≡1(mod n),即x²-1≡0(mod n),可以得到n|(x²-1),运用初中就教的平方差公式得n|(x-1)(x+1)。

         此时我们可以设n=ab,则a|(x-1),b|(x+1)或a|(x+1),b|(x-1)。我们可以用根号n的时间复杂度来枚举a,得到b,然后用b来枚举这两种情况下的x,找出满足条件的x并记录下来。

#include <cstdio>
#include <cmath>
#include <set>

using namespace std;

int n, srn;
set<int> s;

int main()
{
    scanf("%d", &n);
    srn = sqrt(n);
    for(register int i = 1, j; i <= srn; ++i) 
    {
        if(n % i) continue;
        j = n / i;
        for(register int k = j - 1; k < n; k += j)
        {
            if((k - 1) % i) continue;
            s.insert(k);
        }
        for(register int k = 1; k < n; k += j)
        {
            if((k + 1) % i) continue;
            s.insert(k);
        }
    }
    while(!s.empty())
    {
        printf("%d\n", *s.begin());
        s.erase(s.begin());
    }
    return 0;
}
参考程序

猜你喜欢

转载自www.cnblogs.com/kcn999/p/10352727.html