SPOJ NUMTRYE Number Theory (Easy) (pollard_rho分解质因数)

来源:互联网 发布:网络女主播真实收入 编辑:程序博客网 时间:2024/06/05 05:32

SPOJ NUMTRYE Number Theory (Easy)

题意:

g(n)=i=1nngcd(n,i)f(n)=i=1n(p2ki+1i+1)f(n)g(n)%1000000007.n1012

思路:

n=pk11pk22...pkss

g(n)=(p2k1+11+1)(p2k2+12+1)...(p2ks+1s+1)(p1+1)(p2+1)...(ps+1)

f(n)g(n)=(p1+1)(p2+1)(pk+1)

至于如何证明可以参考acdreamer大神的博客:
最大公约数和最小公倍数
以及这篇论文:https://cs.uwaterloo.ca/journals/JIS/VOL13/Toth/toth10.pdf

弱表示只能打表找规律啊!
知道上面规律之后呢,你直接写质因数分解 O(n) 面对10000个cases是会TLE的.
所以还得换成pollard_rho算法来分解质因数,
pollard_rho 俗称泼辣的肉 算法时间理论复杂度为 O(n14) ,乘以 O(t) 刚好够。

不过这题也有一种剪枝水过的方法。。就是数据里很多都是素数,在计算之前先进行素性检验可以优化一下。这样就可以不用写pollard_rho算法,直接质因数分解也能过。

代码:

/** @author FreeWifi_novicer* language : C++/C*/#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<map>#include<set>#include<vector>#include<queue>using namespace std;#define clr( x , y ) memset(x,y,sizeof(x))#define cls( x ) memset(x,0,sizeof(x))#define pr( x ) cout << #x << " = " << x << endl #define pri( x ) cout << #x << " = " << x << " " #define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )#define out( kase ) printf( "Case %d: " , kase++ )#define mp make_pair#define pii pair<int,int>#define pb push_backtypedef long long lint;typedef long long ll;typedef long long LL;const int S = 8 ;const int mod = 1e9 + 7 ;lint multi_mod( lint a , lint b , lint c ){    a %= c ; b %= c ;    lint res = 0 ;    while( b ){        if( b & 1 ){            res += a ;            if( res > c ) res -= c ;        }        a <<= 1 ;        if( a > c ) a-= c ;        b >>= 1 ;    }    return res ;}lint pow_mod( lint x , lint n , lint p ){    x %= p ;    lint res = 1 ;    while( n ){        if( n & 1 )            res = multi_mod( res , x , p ) ;        n >>= 1 ;        x = multi_mod( x , x , p ) ;    }    return res ;}bool check( lint a , lint n , lint x , lint t ){    lint res = pow_mod( a , x , n ) ;    lint last = res ;    for( int i = 0 ; i < t ; i++ ){        res = multi_mod( res , res , n ) ;        if( res == 1 && last != 1 && last != n - 1 ) return true ;        last = res ;    }    if( res != 1 ) return true ;    return false ;}bool Miller_Rabin( lint n ){    if( n < 2 ) return false ;    if( n == 2 ) return true ;    if( ( n & 1 ) == 0 ) return false ;    lint x = n - 1 ;    lint t = 0 ;    while( ( x & 1 ) == 0 ){ x >>= 1 ; t++ ; }    srand( time( NULL ) ) ;    for( int i = 0 ; i < S ; i++ ){        lint a = rand() % ( n - 1 ) + 1 ;        if( check( a , n , x , t ) )            return false ;    }    return true ;}lint factor[100] ;int tol ;lint gcd( lint a , lint b ){    return ( b == 0 )? a : gcd( b , a % b ) ;}lint pollard_rho( lint x , lint c ){    lint i = 1 , k = 2 ;    srand( time( NULL ) ) ;    lint x0 = rand() % ( x - 1 ) + 1 ;    lint y = x0 ;    while( 1 ){        i++ ;        x0 = ( multi_mod( x0 , x0 , x ) + c ) % x ;        lint d = gcd( ( y - x0 + x ) % x , x ) ;        if( d != 1 && d != x ) return d ;        if( y == x0 ) return x ;        if( i == k ){ y = x0 ; k += k ; }    }}// k = 107void findfac( lint n , lint k ){    if( n == 1 ) return ;    if( Miller_Rabin(n) ){        factor[tol++] = n ;        return ;    }    lint p = n ;     int c = k ;    while( p >= n )        p = pollard_rho( p , c-- ) ;    findfac( p , k ) ;    findfac( n / p , k ) ;}lint pf[100][2] ;int getPrifac( lint n ){    tol = 0 ;    findfac( n , 107 ) ;    sort( factor , factor + tol ) ;    cls( pf ) ;    pf[0][0] = factor[0] ;    pf[0][1] = 1 ;    int k = 0 ;    for( int i = 1 ; i < tol ; i++ ){        if( factor[i] != factor[i-1] ) pf[++k][0] = factor[i] ;        pf[k][1] ++ ;    }    return k + 1 ;}lint calc( lint n ){    int len = getPrifac( n ) ;    lint res = 1 ;    for( int i = 0 ; i < len ; i++ ){        res = res % mod * ( pf[i][0] + 1 ) % mod ;    }    return res % mod ;}int main(){//  freopen("input.txt","r",stdin);    test(t){        lint n ;        scanf( "%lld" , &n ) ;        printf( "%lld\n" , calc(n) ) ;    }    return 0;}
0 0