HDU 4344 Mark the Rope

Millar-Rabin +Pollard Rho

我的MR在输入2的时候会挂,因为模0了;

我的PR在输入4的时候会挂,因为出现一点偏差详见代码注释……

关于Pollard Rho推荐:https://wenku.baidu.com/view/3db5c7a6ad51f01dc381f156.html

我也不知道为什么那样子做复杂度是对的…..

实测,像什么x = x * 2333 + c的函数都不如文章里说的x = x * x + c来得快,感觉挺玄学……没找到什么文献,如果有相关的东西求告知……

#include<cstdio>
#include<algorithm>
using namespace std;
namespace runzhe2000
{
    typedef unsigned long long ll;
    ll n, cur; const ll A = 20000107, B = 3333331; 
    ll randll(){return cur = cur * A + B;}
    ll fmul(ll a, ll b, ll p)
    {
        ll r = 0;
        for(; b; b >>= 1)
        {
            if(b&1)(r+=a)%=p;
            (a+=a)%=p;
        }
        return r;
    }
    ll fpow(ll a, ll b, ll p)
    {
        ll r = 1;
        for(; b; b >>= 1)
        {
            if(b&1)r=fmul(r,a,p);
            a=fmul(a,a,p);
        }
        return r;
    }
    int MR(ll n)
    {
        if(n == 2) return true;
        ll a = n-1, b = 0;
        for(; !(a&1); a>>=1, b++);
        for(int t = 10; t; t--)
        {
            ll x = randll()%(n-2)+2, pre;
            x = pre = fpow(x, a, n);
            for(int i = 0; i < (int)b; i++)
            {
                x = fmul(x,x,n);
                if(x==1&&pre!=1&&pre!=n-1)return false;
                pre = x;
            }
            if(x != 1) return false;
        }
        return true;
    }
    ll gcd(ll a, ll b){return b?gcd(b,a%b):a;}
    ll PR(ll n, int c)
    {
        if(n == 4) return 2; //在模4意义下,两次循环以后就相等了,我也不知道为什么这么巧 
        ll x = 2, y = 2, p = 1;
        for(; p == 1; )
        {
            x = fmul(x,x,n)+c;
            y = fmul(y,y,n)+c;
            y = fmul(y,y,n)+c;
            if(x == y) return n;
            p = gcd(n, (y-x+n)%n);
        }
        return p;
    }
    ll ans, q[2333333]; int tail;
    void find(ll x, int c)
    {
        if(x == 1) return;
        if(MR(x))q[tail++] = x;
        else
        {
            ll p = x;
            for(; p==x; ) p = PR(x,c++);
            find(x/p, c); find(p, c);
        }
    }
    void main()
    {
        int T; scanf("%d",&T);
        for(; T--; )
        {
            scanf("%lld",&n);
            tail = ans = 0; find(n,1);
            sort(q, q+tail); int cnt = 0;
            ll tmp = 0;
            for(int i = 0; i < tail; i++)
            {
                if(q[i] != q[i-1])
                {
                    ans += tmp;
                    ++cnt;
                    tmp = 1;
                }
                tmp *= q[i];
            }
            ans += tmp;
            if(cnt == 1) ans /= q[0];
            printf("%d %lld\n",cnt, ans);
        }
    }
}
int main()
{
    runzhe2000::main();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值