zoukankan      html  css  js  c++  java
  • hdu 4344 Mark the Rope(Miller_Rabbin+Pollard_Rho)

    呃,有好久没写博了,很无奈呢,每次做完题总是会忘了这最后一步。。。。

    这题是上次比赛的一道题,比赛中就认为这题有技巧,其实在比赛中XH就找到了结论,但是由于当时我们俩都没接触过快速判素和快速求质因子的方法,也就是Miller_Rabbin和Pollard_Rho方法,所以尝试了几次打表,结果没过,然后就不了了之了。赛后看了解题报告,知道思路没错,有用打表的方法做了两遍,还是原样,题解中说用到了Pallard_Rab求质因子,所以就上网搜搜了,然后直到今天才做这题。

    题意:求出N的所有因子,然后选出尽可能多的元素,是的选出的元素两两互质,求出最长的长度和这些元素的最大和。

    思路:为了尽可能多的选出,每个L的质因子应当只包含N的一个质因子,L是一个质因子的整数次,所以K的值就是N中不同质因子的个数, 要想和最大,那么使得每个L最大,只要使得质因子的指数最大即可。

    再来说说上面的两个定理:

    Miller_Rabbin:是根据费马小定理而推出的一种有随机数来判断一个数是否是质数,原理我看了一篇百度贴吧里的文章明白的,给出网址,有兴趣可以去看看。

    http://tieba.baidu.com/p/129366421

    Pollard_Rho:我觉得想弄懂这个算法,还是要看算法导论的,第三十一章的整数的因子分解。

    代码:

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <math.h>
    #define  N 205
    using namespace std ;
    
    typedef long long ll ;
    
    ll f[N] , n ;
    int num ;
    
    //求x,y的最大公约数
    ll gcd( ll x , ll y )
    {
        if ( !y )
        return x ;
        else
        return gcd( y , x % y ) ;
    }
    
    //求a*b
    ll Multip ( ll a , ll b , ll n )
    {
        ll k = a % n ;
        ll res = 0 ;
    
        while( b )
        {
            if ( b & 1 )
            {
                res += k ;
                if ( res > n )
                res -= n ;
            }
            k <<= 1 ;
            if ( k > n )
            k -= n ;
            b >>= 1 ;
        }
        return res ;
    }
    
    //求(a^b)mod n
    ll Exp_mod( ll a , ll b , ll n )
    {
        ll s = 1 ;
        while( b )
        {
            if ( b & 1 )
            s = Multip( s , a , n );
            a = Multip ( a , a , n );
            b >>= 1;
        }
        return s ;
    }
    
    //判断n是否是素数,c代表测试的次数
    bool Miller_Rabbin( ll n , ll c )
    {
        if ( n == 2 )
        return true ;
        if ( n < 2 || !( n & 1))
        return false ;
    
        int t = 0 ;
        ll x , y , a ;
        ll m = n - 1 ;
        while( m % 2 == 0 )
        {
            t++ ;
            m /= 2 ;
        }
    
        srand( 100 );
        for ( int i = 0 ; i < c ; i++ )
        {
            a = rand() % ( n - 1 ) + 1 ;
            x = Exp_mod( a , m , n );
            for ( int j = 0 ; j < t ; j++ )
            {
                y = Multip( x , x ,n );
                if ( y == 1 && x != 1 && x != n - 1 )
                return false ;
                x = y ;
            }
            if ( y != 1 )
            return false ;
        }
        return true ;
    }
    
    //求n的质因子
    ll Pallard_Rab( ll n , ll c )
    {
        int i = 1 , k = 2 ;
        ll x , y , d ;
        x = y = rand() % ( n -1 ) + 1 ;
        while( 1 )
        {
            i++ ;
            x = ( Multip( x , x , n ) + c ) % n ;
            d = gcd ( ( x - y + n ) % n , n );
            if ( d > 1 && d < n )
            return d ;
            if ( x == y )
            return n ;
            if ( i == k )
            {
                k <<= 1 ;
                y = x ;
            }
        }
    }
    
    //求出N的所有质因子,并记录
    void Find_factors( ll n  , ll c )
    {
        if ( n == 1 )
        return ;
    
        if ( Miller_Rabbin( n , 6 ))
        {
            f[num++] = n ;
            return ;
        }
    
        ll p = n ;
        ll k = c ;
        while( p >= n )
        p = Pallard_Rab( p , c-- );
        Find_factors( p , k );
        Find_factors( n / p , k );
    }
    //  a^b
    ll powx( ll a , ll b )
    {
        ll s = 1 ;
        for ( int i = 0 ; i < b ; i++ )
        s *= a ;
        return s ;
    }
    
    int main()
    {
        int cas , i ;
    
        cin>>cas ;
        while( cas-- )
        {
            cin>>n ;
            num = 0 ;
            Find_factors( n , 120 );
            map<ll , int>ms ;
            for ( i = 0 ; i < num ; i++ )
            ms[f[i]]++ ;
            int s = ms.size();
            if ( s == 1 )
            {
                cout<<s<<" "<<( n / f[0] )<<endl ;
            }
            else
            {
                ll sum = 0 ;
                map<ll , int>::iterator it ;
                for ( it = ms.begin() ; it != ms.end() ; it++ )
                {
                    sum += powx ( it->first , it->second) ;
                }
                cout<<s<<" "<<sum<<endl;
            }
        }
        return 0 ;
    }
  • 相关阅读:
    PAT 甲级 1132 Cut Integer (20 分)
    AcWing 7.混合背包问题
    AcWing 9. 分组背包问题
    AcWing 5. 多重背包问题 II
    AcWing 3. 完全背包问题
    AcWing 4. 多重背包问题
    AcWing 2. 01背包问题
    AcWing 875. 快速幂
    AcWing 874. 筛法求欧拉函数
    AcWing 873. 欧拉函数
  • 原文地址:https://www.cnblogs.com/misty1/p/2633077.html
Copyright © 2011-2022 走看看