BZOJ1406: [AHOI2007]密码箱 数论

Description

在一次偶然的情况下,小可可得到了一个密码箱,听说里面藏着一份古代流传下来的藏宝图,只要能破解密码就能打开箱子,而箱子背面刻着的古代图标,就是对密码的提示。经过艰苦的破译,小可可发现,这些图标表示一个数以及这个数与密码的关系。假设这个数是n,密码为x,那么可以得到如下表述: 密码x大于等于0,且小于n,而x的平方除以n,得到的余数为1。 小可可知道满足上述条件的x可能不止一个,所以一定要把所有满足条件的x计算出来,密码肯定就在其中。计算的过程是很艰苦的,你能否编写一个程序来帮助小可可呢?(题中x,n均为正整数)

Input

输入文件只有一行,且只有一个数字n(1<=n<=2,000,000,000)。

Output

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

Sample Input

12

Sample Output

1
5
7
11

Solution

首先考虑怎么去掉这个mod

$$x^2\ mod\ n\ =\ 1 $$

可以化为

$$kn=x^2-1$$

$$kn=(x+1)(x-1)$$

即$$n|(x+1)(x-1)$$

所以枚举$n$的因数来算就好,注意要枚举大因数,小因数TLE的很惨...

可以拿set来存答案也可以最后把答案排序一遍

#include <bits/stdc++.h>

#define ll long long
#define inf 0x3f3f3f3f
#define il inline

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('\n')

    #define I_int ll
    inline I_int read() {
        I_int x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
    }
    #undef I_int

}
using namespace io ;

using namespace std ;

#define N 100010

//x^2 mod n = 1
//kn = x^2 - 1 
//n | x^2 - 1
//n | (x+1)(x-1) 

ll n = read() ; 
ll st[ N ] ;
int top = 0 ;
int cnt[ N ] ;

int main() {
    for( ll i = 1 ; i * i <= n ; i ++ ) {
        if( n % i == 0 ) {
            st[ ++ top ] = n / i ;
        }
    }
    int tot = 0 ;
    while( top ) {
        ll tmp = st[ top ] ;
        for( ; tmp <= n ; tmp += st[ top ] ) {
            if( ( tmp - 2 ) % ( n / st[ top ] ) == 0 ) 
                cnt[ ++ tot ] = ( tmp - 1 ) % n ;
            if( ( tmp + 2 ) % ( n / st[ top ] ) == 0 ) 
                cnt[ ++ tot ] = ( tmp + 1 ) % n ;
        }
        top -- ;
    }
    if( !tot ) puts("None") ;
    else {
        sort( cnt + 1 , cnt + tot + 1 ) ;
        for( int i = 1 ; i <= tot ; i ++ ) {
            if( cnt[ i ] != cnt[ i - 1 ] ) outn( cnt[ i ] ) ;
        }
    }
    return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/henry-1202/p/BZOJ1406.html