您的位置:首页 > Web前端

[Asia - Hefei - 2008/2009][B:Discrete Square Roots][数论基础] 还是不是很懂,先转

2010-09-15 18:34 441 查看
 

看了一下问题,大家可以到ACM/ICPC的那个网站上搞到题目

A square root of a number x is a number r such that r2 = x . A discrete square root of a non-negative integer x
is a non-negative integer r such that r2  x mod N , 0 r < N , where N is a specific positive integer and mod
is the modulo operation.
It is well-known that any positive real number has exactly two square roots, but a non-negative integer may
have more than two discrete square roots. For example, for N = 12 , 1 has four discrete square roots 1, 5, 7 and
11.
Your task is to find all discrete square roots of a given non-negative integer x . To make it easier, a known
square root r of x is also given to you.

类似于此。。然后意淫搞。。可以用中国剩余定理。。但是总之,感觉现在的ACM变成了YY大赛。。总给人很没劲的感觉。。。

看一篇解题报告吧。。YY的很。

来自百度空间 http://hi.baidu.com/aekdycoin/blog/item/5f8f02888ae1a6b80f24449b.html

【题目大意:】
给出x,N,r,保证 r^2 = x (mod N),现在要你求出所有解

【数据规模:】
(1

x < N, 2

N < 1, 000, 000, 000, 1

r < N)
【解题思路:】
由于N是任意数,所以对于N不一定存在原根,于是就不能用指标来做。
可是由于他告诉你一个解,所以,我们可以通过以下的转换得到解决方案

假设存在另一个跟r',那么有
(r' + r) (r'-r) = 0(mod N) ……………………………………(1)
那么显然我们可以得到下面结论
(1)  N |  (r'+r) * (r' - r)  (显然)
(2) (r'+r) (r'-r) 中包含了N的所有素因子集合

假设 r'+r 包含的素因子集合为Pi,那么显然 r'+r = k1 * Pi
同样我们就可以得到 r'-r = k2 * (N / Pi) 
这样2个数乘起来才能满足条件(1)
其中ki,k2>=0
于是我们容易得到
r' = -r (mod Pi)
r' = r  (mod N/Pi)


那显然我们只需要找到所有r'<N的满足上述条件的r'都是解了.
由于 (Pi,N/Pi) 不一定为1,所以可以使用合并方程的做法来做,并可以在合并后得到一个最小解
然后通过暴力枚举,得到r' < N的所有解
至于为什么这里可以暴力枚举,实际上完全可以证明暴力的次数不多。
因为我们知道,最小解 + k * lcm(Pi,N/Pi) 可以生成所有解,只需要证明 lcm(Pi,N/Pi)相对N不会很小就可以了
(1)如果(Pi,N/Pi) == 1,那么显然lcm() = N,那么显然解唯一了(<N内)
(2)如果(Pi,N/Pi) != 1,我们来一个极端情况,假设Pi <= N/Pi, 那么我们可以知道(Pi,N/Pi)<=Pi
而对于Pi来说,由于Pi <= N/Pi,所以可以确定Pi<= sqrt(N)
那么由于N<=10^9,显然Pi就很小,于是lcm(Pi,N/Pi) = N / (Pi,N/Pi) >= N/Pi
由于Pi<=sqrt(N),所以...嘿嘿不要我多说了吧,于是枚举次数大约为sqrt(N) (实际上大部分情况远小),完全可以接受

然后对解排序以后输出就可以了

【举例说明:】

对于第一组数据

1 12 1

N = 12
那么我们枚举N的因子
由r' = -r (mod Pi)

r' = r  (mod N/Pi)
得到:

r' = -1(mod 1)
r' = 1 (mod 12)   ==>  r' = 1 lcm(1,12) = 12, 显然1 + 12 >= 12(13 显然不是解)

 

r' = -1(mod 2)
r' = 1 (mod 6)   ==>  r' = 1 (最小解) lcm(2,6) = 6, 显然1 + 6 = 7 < 12 (新解), 7 + 6 = 13 >= 12
(13 显然不是解)

r' = -1(mod 3)
r' = 1 (mod 4)   ==>  r' = 5 lcm(3,4) = 12, 显然5 + 12 >= 12
(17 显然不是解)

。。。
。。。

于是得到解
1 5 7 11

【总结:】
此题考察了数论中的基本递推,以及方程的合并,还是比较中规中矩的,难度上并不会太大

ll x , N , r ;
ll gcd( ll a , ll b ){
if( b == 0 ) return a ;
return gcd( b , a%b ) ;
}
ll _lcm( ll a , ll b ){
ll g = gcd( a , b ) ;
return a/g*b ;
}
ll c[ 10 ] , m[ 10 ] ;
ll mod( ll  x , ll y )
{
ll res = x%y ;
if( res < 0 ) res += y ;
return res ;
}
// x≡ c[]%m[] ;
// a x + b y = 1  返回 gcd( a , b ) = 1  x为其中一个解
ll exp_gcd( ll a , ll b , ll &x , ll &y ){
ll q , _temp ;
if( b == 0 ){
q = a ; x = 1 ; y = 0 ;
return q ;
}
else{
q = exp_gcd( b , a%b , x , y ) ;
_temp = x ; x = y ; y = _temp - (a/b )*y ;
return q ;
}
}
ll solve( int n )
{
ll ans = c[ 1 ] , _LCM = m[ 1 ]  ;
ll x , y , g , mm ;
for( int i = 2 ; i <= n ; i ++ ) {
g = exp_gcd( _LCM , m[ i ] , x , y ) ;
if( ( c[ i] - ans )%g )
return -1 ;
ans = mod( ans + _LCM*mod( ( c[ i ] - ans )/g*x , m[ i ]/g ) , _LCM/g*m[ i ] ) ;
_LCM = _LCM/g*m[ i ] ;
}
return ans ;
}

vector<ll> fac ;
vector<ll> vec ;
int main()
{
int cas = 1 ;
while( scanf("%lld %lld %lld", &x,&N,&r ) != EOF ){
if( x == 0 && N ==0 && r == 0 ) break ;
fac.clear() ;
vec.clear() ;
for( ll i = 1 ; i*i <= N ; i ++ ){
if( N%i == 0 ) {
fac.push_back( i ) ;
fac.push_back( N/i ) ;
}
}
vec.push_back( r ) ;
int i ;
for(  i = 0 ; i < fac.size() ; i ++ ){
m[ 1 ] = fac[ i ] ;
m[ 2 ] = N/fac[ i ] ;
c[ 1 ] = ( -1*r + fac[ i ] )%m[ 1 ] ;
c[ 2 ] = r%m[ 2 ] ;
ll _MIN = solve( 2 ) ;
if( _MIN == -1 ) continue ;
ll A = _lcm( m[ 1 ] , m[ 2 ] ) ;
while( _MIN < N ){
vec.push_back( _MIN ) ;
_MIN += A ;
}
}
sort( vec.begin() , vec.end() ) ;
printf("Case %d: %lld",cas ++,vec[ 0 ] ) ;
for( i = 1 ; i < vec.size() ; i ++ ){
if( vec[ i ] != vec[ i - 1 ] ) printf(" %lld",vec[ i ] ) ;
}
printf("/n") ;
}
return 0 ;
}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  integer c 百度