题目链接:
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 );
}
}