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 ;
    }
  • 相关阅读:
    MongoDB学习笔记(二)
    mongoDB学习笔记(一)
    docker官方文档笔记
    nagios
    网络流量状态命令总结 (含notp安装)
    other
    一键搭建LNMP脚本
    linux问题总结
    linux中VI编写C程序。。。
    centos 7 安装python3.5.1
  • 原文地址:https://www.cnblogs.com/misty1/p/2633077.html
Copyright © 2011-2022 走看看