bzoj 3283 扩展BSGS + 快速阶乘
T2 扩展BSGS
T3 快速阶乘
给定整数n,质数p和正整数c,求整数s和b,满足n! / pb = s mod pc
考虑每次取出floor(n/p)个p因子,然后将问题转化为子问题。
1 /************************************************************** 2 Problem: 3283 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1704 ms 7 Memory:12380 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <cmath> 13 14 typedef long long dnt; 15 void exgcd( dnt a, dnt b, dnt &d, dnt &x, dnt &y ) { 16 if( b==0 ) { 17 x=1, y=0, d=a; 18 } else { 19 exgcd(b,a%b,d,y,x); 20 y-=a/b*x; 21 } 22 } 23 dnt inv( int a, int n ) { 24 dnt d, x, y; 25 exgcd(a,n,d,x,y); 26 return d==1 ? (x%n+n)%n : -1; 27 } 28 dnt mpow( dnt a, dnt b, dnt c ) { 29 dnt rt; 30 for( rt=1; b; b>>=1,a=a*a%c ) 31 if( b&1 ) rt=rt*a%c; 32 return rt; 33 } 34 35 namespace Task1 { 36 void sov( dnt a, dnt b, dnt c ) { 37 printf( "%lld\n", mpow(a,b,c) ); 38 } 39 }; 40 namespace Task2 { 41 const int mod = 38281; 42 const int len = mod<<3; 43 struct Hash { 44 int head[mod], val[len], rat[len], next[len], ntot; 45 void init() { 46 ntot=0; 47 memset( head, 0, sizeof(head) ); 48 } 49 void insert( int v, int r ) { 50 int k = v % mod; 51 ntot++; 52 next[ntot] = head[k]; 53 val[ntot] = v; 54 rat[ntot] = r; 55 head[k] = ntot; 56 } 57 int query( int v ) { 58 int k = v % mod; 59 for( int t=head[k]; t; t=next[t] ) 60 if( val[t]==v ) return rat[t]; 61 return -1; 62 } 63 }hash; 64 65 dnt gcd( dnt a, dnt b ) { 66 return b ? gcd(b,a%b) : a; 67 } 68 int bsgs( dnt s, dnt a, dnt b, dnt c ) { 69 hash.init(); 70 int m = ceil(sqrt(c)); 71 for( int i=0; i<m; i++ ) { 72 if( s==b ) return i; 73 hash.insert( s, i ); 74 s = s*a % c; 75 } 76 dnt am = 1; 77 for( int i=0; i<m; i++ ) 78 am = am*a % c; 79 am = inv(am,c); 80 b = b*am % c; 81 for( int i=m; i<c; i+=m ) { 82 int j = hash.query( b ); 83 if( j!=-1 ) return i+j; 84 b = b*am % c; 85 } 86 return -1; 87 } 88 int exbsgs( dnt a, dnt b, dnt c ) { 89 dnt s = 1; 90 for( int i=0; i<32; i++ ) { 91 if( s==b ) return i; 92 s = s*a % c; 93 } 94 dnt cd; 95 s = 1; 96 int rt = 0; 97 while( (cd=gcd(a,c))!=1 ) { 98 rt++; 99 s*=a/cd; 100 if( b%cd ) return -1; 101 b/=cd; 102 c/=cd; 103 s%=c; 104 } 105 int p = bsgs(s,a,b,c); 106 if( p==-1 ) return -1; 107 return rt + p; 108 } 109 void sov( int a, int b, int c ) { 110 int res = exbsgs(a,b,c); 111 if( res==-1 ) printf( "Math Error\n" ); 112 else printf( "%d\n", res ); 113 } 114 }; 115 namespace Task3 { 116 struct Pair { 117 int s, k; 118 Pair( int s, int k ):s(s),k(k){} 119 }; 120 dnt aa[50], mm[50]; 121 dnt pres[1001000]; 122 dnt pp[50], cc[50], ppp[50], tot; 123 124 dnt china( int n, dnt *a, dnt *m ) { 125 int M=1; 126 for( int i=0; i<n; i++ ) 127 M *= m[i]; 128 int rt = 0; 129 for( int i=0; i<n; i++ ) { 130 dnt Mi = M/m[i]; 131 rt = (rt+Mi*inv(Mi,m[i])*a[i]) % M; 132 } 133 return rt; 134 } 135 void init( int p, int pp ) { 136 pres[0] = 1; 137 for( int i=1; i<=pp; i++ ) { 138 if( i%p==0 ) { 139 pres[i] = pres[i-1]; 140 } else { 141 pres[i] = pres[i-1]*i % pp; 142 } 143 } 144 } 145 Pair split( int n, int p, int c, int pp ) { 146 int b = n/p; 147 if( b==0 ) { 148 return Pair( pres[n], 0 ); 149 } else { 150 Pair pr = split( b, p, c, pp ); 151 return Pair( (pr.s*pres[n%pp]%pp) * mpow(pres[pp],n/pp,pp) % pp, pr.k+b ); 152 } 153 } 154 void sov( int m, int n, int c ) { 155 tot = 0; 156 for( int i=2; i*i<=c; i++ ) { 157 if( c%i==0 ) { 158 pp[tot] = i; 159 cc[tot] = 0; 160 ppp[tot] = 1; 161 while( c%i==0 ) { 162 cc[tot]++; 163 ppp[tot] *= pp[tot]; 164 c/=i; 165 } 166 tot++; 167 } 168 } 169 if( c!=1 ) { 170 pp[tot] = c; 171 cc[tot] = 1; 172 ppp[tot] = c; 173 tot++; 174 c = 1; 175 } 176 for( int i=0; i<tot; i++ ) { 177 init(pp[i],ppp[i]); 178 Pair pn = split( n, pp[i], cc[i], ppp[i] ); 179 Pair pa = split( m, pp[i], cc[i], ppp[i] ); 180 Pair pb = split( n-m, pp[i], cc[i], ppp[i] ); 181 if( pn.k-pa.k-pb.k >= cc[i] ) { 182 aa[i] = 0; 183 mm[i] = ppp[i]; 184 } else { 185 aa[i] = pn.s * (inv(pa.s,ppp[i])*inv(pb.s,ppp[i])%ppp[i]) % ppp[i]; 186 for( int j=0; j<pn.k-pa.k-pb.k; j++ ) 187 aa[i] = (dnt) aa[i]*pp[i] % ppp[i]; 188 mm[i] = ppp[i]; 189 } 190 } 191 /* 192 fprintf( stderr, "tot=%d\n", tot ); 193 for( int i=0; i<tot; i++ ) 194 fprintf( stderr, "%d %d\n", aa[i], mm[i] ); 195 */ 196 printf( "%lld\n", china(tot,aa,mm) ); 197 } 198 }; 199 200 int main() { 201 int n; 202 scanf( "%d", &n ); 203 for( int i=1,opt,y,z,p; i<=n; i++ ) { 204 scanf( "%d%d%d%d", &opt, &y, &z, &p ); 205 if( opt==1 ) 206 Task1::sov( y, z, p ); 207 else if( opt==2 ) 208 Task2::sov( y, z, p ); 209 else 210 Task3::sov( y, z, p ); 211 } 212 }