bzoj 3283: 運算器

題目鏈接:

https://www.lydsy.com/JudgeOnline/problem.php?id=3283

快速冪+拓展lucas+拓展GSBS

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void exgcd( ll a, ll b, ll &d, ll &x, ll &y )
{
    if( b==0 )
    {
        x=1, y=0, d=a;
    }
    else
    {
        exgcd(b,a%b,d,y,x);
        y-=a/b*x;
    }
}
ll inv( int a, int n )
{
    ll d, x, y;
    exgcd(a,n,d,x,y);
    return d==1 ? (x%n+n)%n : -1;
}
ll poww( ll a, ll b, ll mod )
{
      ll res=1;
      while(b)
      {
          if(b&1) res=res*a%mod;
          b/=2;
          a=a*a%mod;
      }
      return res%mod;
}

namespace Task1
{
    void sov( ll a, ll b, ll c )
    {
        printf("%lld\n", poww(a,b,c));
    }
};
namespace Task2
{
    const int mod = 38281;
    const int len = mod<<3;
    struct Hash
    {
        int head[mod], val[len], rat[len], next[len], ntot;
        void init()
        {
            ntot=0;
            memset( head, 0, sizeof(head) );
        }
        void insert( int v, int r )
        {
            int k = v % mod;
            ntot++;
            next[ntot] = head[k];
            val[ntot] = v;
            rat[ntot] = r;
            head[k] = ntot;
        }
        int query( int v )
         {
            int k = v % mod;
            for( int t=head[k]; t; t=next[t] )
                if( val[t]==v ) return rat[t];
            return -1;
        }
    }hash;

    ll gcd( ll a, ll b )
    {
        return b ? gcd(b,a%b) : a;
    }
    int bsgs( ll s, ll a, ll b, ll c )
    {
        hash.init();
        int m = ceil(sqrt(c));
        for( int i=0; i<m; i++ )
        {
            if( s==b ) return i;
            hash.insert( s, i );
            s = s*a % c;
        }
        ll am = 1;
        for( int i=0; i<m; i++ )
            am = am*a % c;
        am = inv(am,c);
        b = b*am % c;
        for( int i=m; i<c; i+=m )
        {
            int j = hash.query( b );
            if( j!=-1 ) return i+j;
            b = b*am % c;
        }
        return -1;
    }
    int exbsgs( ll a, ll b, ll c )
    {
        ll s = 1;
        for( int i=0; i<32; i++ )
        {
            if( s==b ) return i;
            s = s*a % c;
        }
        ll cd;
        s = 1;
        int rt = 0;
        while( (cd=gcd(a,c))!=1 )
        {
            rt++;
            s*=a/cd;
            if( b%cd ) return -1;
            b/=cd;
            c/=cd;
            s%=c;
        }
        int p = bsgs(s,a,b,c);
        if( p==-1 ) return -1;
        return rt + p;
    }
    void sov( int a, int b, int c )
    {
        int res = exbsgs(a,b,c);
        if( res==-1 ) printf( "Math Error\n" );
        else printf( "%d\n", res );
    }
};
namespace Task3
{
    struct Pair
    {
        int s, k;
        Pair( int s, int k ):s(s),k(k){}
    };
    ll aa[50], mm[50];
    ll pres[1001000];
    ll pp[50], cc[50], ppp[50], tot;

    ll china( int n, ll *a, ll *m )
    {
        int M=1;
        for( int i=0; i<n; i++ )
            M *= m[i];
        int rt = 0;
        for( int i=0; i<n; i++ )
        {
            ll Mi = M/m[i];
            rt = (rt+Mi*inv(Mi,m[i])*a[i]) % M;
        }
        return rt;
    }
    void init( int p, int pp )
    {
        pres[0] = 1;
        for( int i=1; i<=pp; i++ )
        {
            if( i%p==0 ) {
                pres[i] = pres[i-1];
            } else {
                pres[i] = pres[i-1]*i % pp;
            }
        }
    }
    Pair split( int n, int p, int c, int pp )
    {
        int b = n/p;
        if( b==0 )
        {
            return Pair( pres[n], 0 );
        }
        else
        {
            Pair pr = split( b, p, c, pp );
            return Pair( (pr.s*pres[n%pp]%pp) * poww(pres[pp],n/pp,pp) % pp, pr.k+b );
        }
    }
    void sov( int m, int n, int c )
    {
        tot = 0;
        for( int i=2; i*i<=c; i++ )
        {
            if( c%i==0 )
            {
                pp[tot] = i;
                cc[tot] = 0;
                ppp[tot] = 1;
                while( c%i==0 )
                {
                    cc[tot]++;
                    ppp[tot] *= pp[tot];
                    c/=i;
                }
                tot++;
            }
        }
        if( c!=1 )
        {
            pp[tot] = c;
            cc[tot] = 1;
            ppp[tot] = c;
            tot++;
            c = 1;
        }
        for( int i=0; i<tot; i++ )
        {
            init(pp[i],ppp[i]);
            Pair pn = split( n, pp[i], cc[i], ppp[i] );
            Pair pa = split( m, pp[i], cc[i], ppp[i] );
            Pair pb = split( n-m, pp[i], cc[i], ppp[i] );
            if( pn.k-pa.k-pb.k >= cc[i] )
            {
                aa[i] = 0;
                mm[i] = ppp[i];
            }
            else
            {
                aa[i] = pn.s * (inv(pa.s,ppp[i])*inv(pb.s,ppp[i])%ppp[i]) % ppp[i];
                for( int j=0; j<pn.k-pa.k-pb.k; j++ )
                    aa[i] = (ll) aa[i]*pp[i] % ppp[i];
                mm[i] = ppp[i];
            }
        }
        printf( "%lld\n", china(tot,aa,mm) );
    }
};

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int opt,y,z,p;
        cin>>opt>>y>>z>>p;
         if(opt==1)
            Task1::sov( y, z, p );
        else if(opt==2)
            Task2::sov( y, z, p );
        else
            Task3::sov( y, z, p );

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章