小技巧函数
字符数组快速求最小字典
原理不多说,用笔在纸上模拟一下就会懂的。
1 int Min_index(char *ss){ 2 int i = 0,j = 1, k = 0; 3 int len = strlen(ss); 4 while(i<len && j<len && k<len){ 5 int t = ss[(j+k)%len]-ss[(i+k)%len]; 6 if(t == 0)k++; 7 else{ 8 if(t>0) j+=k+1; 9 else i+=k+1; 10 k=0; 11 } 12 if(i==j)j++; 13 } 14 return min(i,j); 15 }
同理,也可以快速求最大字典
求质因子,在欧拉函数和莫比乌斯函数用的上。
1 int fun(int x){ 2 int res = 0; 3 for(int i = 2; i <= sqrt(x); i ++){ 4 if(x%i==0){ 5 res++; 6 while(x%i==0)x/=i; 7 } 8 } 9 if(x > 1) res++; 10 return res; 11 }
乘法逆元。a/b%n == a*k%n == a*inv(b,n);
1 void exgcd(ll a, ll b, ll &x, ll &y) { 2 if(!b){ 3 x = 1; y = 0; 4 }else{ 5 exgcd(b, a%b, y, x); 6 y -= x*(a/b); 7 } 8 } 9 ll inv(ll a, ll n) { 10 ll x, y; 11 exgcd(a, n, x, y); 12 return (x+n)%n; 13 }
a*x+b*y=d
void exgcd(ll a, ll b,ll &d, ll &x, ll &y) { if(!b){ d = a; x = 1; y = 0; }else{ exgcd(b, a%b, d, y, x); y -= x*(a/b); } }
上面的乘法有误差6*inv(2,mod)不等于3 费马小定理没有
费马小定理求逆元a/b%mod = a*pow_mod(b,mod-2)%mod
1 ll pow_mod(ll x, ll n){ 2 ll res=1; 3 while(n>0){ 4 if(n&1)res=res*x%mod; 5 x=x*x%mod; 6 n>>=1; 7 } 8 return res; 9 }
基姆拉尔森公式,计算某日是星期几
1 int day(int y, int m, int d) { 2 if(m == 1 || m == 2) { 3 m += 12; 4 y --; 5 } 6 int w = (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7; 7 return w; 8 }
求C(n,m)%p,都是在[1,1e18]范围内
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N = 15; 5 ll qmul(ll a,ll p,ll m){ 6 ll tmp = 0; 7 while(p){ 8 if(1&p) tmp = (tmp+a)%m; 9 a = (a+a)%m; 10 p>>=1; 11 } 12 return tmp; 13 } 14 void exgcd(ll a,ll b,ll &x,ll &y,ll &d){ 15 if(!b) d=a,x = 1,y=0; 16 else exgcd(b,a%b,y,x,d),y-=(a/b)*x; 17 } 18 ll inv(ll a,ll p){ 19 ll x,y,d; 20 exgcd(a,p,x,y,d); 21 return d==1?(x+p)%p:-1; 22 } 23 ll fat(ll x,ll p){ 24 ll ans = 1; 25 for( int i = 2 ; i <= x ; i ++ ) ans = ( ans * i ) % p; 26 return ans; 27 } 28 ll c(ll n,ll m,ll p){ 29 if (m < 0 || m > n) return 0; 30 return fat(n,p)*inv(fat(m,p),p)%p*inv(fat(n-m,p),p)%p; 31 } 32 ll crt(ll *a,ll *m,int n){ 33 ll M = 1,res = 0; 34 for( int i = 0 ; i < n ; i++ ) M*=m[i]; 35 for( int i = 0 ; i < n ; i++ ){ 36 ll w = M/m[i]; 37 res = (res+qmul(w*inv(w,m[i]),a[i],M))%M; 38 } 39 return (res+M)%M; 40 } 41 ll Lucas(ll n,ll m,ll p){ 42 return m?Lucas(n/p,m/p,p)*c(n%p,m%p,p)%p:1; 43 } 44 int main() { 45 ll a[N], p[N]; 46 ll t, n, m, k; 47 cin >> t; 48 while(t--) { 49 cin >> n >> m >> k; 50 for(int i = 0; i < k; i ++) { 51 cin >> p[i]; 52 a[i] = Lucas(n, m, p[i]); 53 } 54 printf("%lld\n",crt(a, p, k)); 55 } 56 return 0; 57 }