辗转相除法 1 2 3 4 5 6 inline ll gcd (ll a, ll b) { if (b == 0 ) return a; else return gcd (b, a % b); }
扩展欧几里德算法 求二元一次方程ax + by = d
,当且仅当d是gcd(a,b)
的倍数时有整数解
1 2 3 4 5 6 7 8 9 10 11 inline ll exGcd (ll a,ll b,ll &x,ll &y) { if (b==0 ){ x=1 ;y=0 ; return a; } ll r=exGcd (b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; return r; }
最小正整数解((x*(d/gcd(a,b))%(b/gcd(a,b)))+(b/gcd(a,b)))%(b/gcd(a,b))
筛法求素数 埃筛 埃筛适用与判断某个数是否质数
1 2 3 4 5 6 7 8 9 10 11 12 13 bool prime[MAXN];inline void eratosthense () { int m = sqrt (MAXN); prime[0 ] = prime[1 ] = 1 ; for (int i = 2 ; i <= m; i++){ if (prime[i]){ continue ; } for (int j = i; j * i < MAXN; j++){ prime[i * j] = 1 ; } } }
欧拉筛 线筛适用与将所有的质数提取出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const int N = 200000 ;int isprime[N/3 ] = {0 },num_prime = 0 ;bool isNotPrime[N] = {1 , 1 };inline void prime (void ) { for (int i = 2 ; i < N ; i ++){ if (!isNotPrime[i]) isprime[num_prime++]=i; for (int j = 0 ; j < num_prime && i * isprime[j] < N; j ++){ isNotPrime[i * isprime[j]] = 1 ; if (!(i % isprime[j])) break ; } } }
莫筛 莫筛是在欧拉筛上面做了一点手脚形成的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const int N = 200000 ; int mu[N], sumu[N];int isprime[N/3 ] = {0 },num_prime = 0 ; int isNotPrime[N] = {1 , 1 }; inline void mobius (void ) { sumu[1 ] = mu[1 ] = 1 ; for (int i = 2 ; i < N ; i ++){ if (! isNotPrime[i]){ isprime[num_prime ++]=i; mu[i] = -1 ; } for (int j = 0 ; j < num_prime && i * isprime[j] < N ; j ++){ isNotPrime[i * isprime[j]] = 1 ; if ( !(i % isprime[j] ) ) break ; mu[isprime[j] * i] = -mu[i]; } } for (int i = 2 ;i < N;i++) sumu[i] = sumu[i-1 ] + mu[i]; }
欧拉函数 欧拉函数,比他小的并与他互质的个数。值得一提的是,素数的欧拉值等于他本身减一。
又双叒是欧拉筛拓展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const int N = 200000 ;int isprime[N/3 ] = {0 },num_prime = 0 ;int phi[N];bool isNotPrime[N] = {1 , 1 };inline void Eular (void ) { phi[1 ] = 1 ; for (int i = 2 ; i < N; i++){ if (!isNotPrime[i]){ isprime[num_prime++]=i; phi[i] = i - 1 ; } for (int j = 0 ; j < num_prime && i * isprime[j] < N; j++){ isNotPrime[i * isprime[j]] = 1 ; if (!(i % isprime[j])){ phi[i * isprime[j]] = phi[i] * isprime[j]; break ; }else phi[i * isprime[j]] = phi[i] * (isprime[j] - 1 ); } } }
唯一分解定理 求一数的因子对数,欧拉yyds
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const int N = 200000 ;int isprime[N/3 ] = {0 },num_prime = 0 ;bool isNotPrime[N] = {1 , 1 };inline void prime (void ) { for (int i = 2 ; i < N; i++){ if (!isNotPrime[i]) isprime[num_prime++]=i; for (int j = 0 ; j < num_prime && i * isprime[j] < N; j++){ isNotPrime[i * isprime[j]] = 1 ; if (!(i % isprime[j])) break ; } } } inline int font (int n) { int ans; if (n == 0 ) return 0 ; int cnt = 0 ; int i; while (isprime[i] < n && i < num_prime){ cnt = 0 ; if (num % isprime[i] == 0 ){ while (num % isprime[i] == 0 ){ cnt++; n /= isprime[i]; } } ans *= cnt+1 ; i++; } if (n > 1 ){ ans *= 2 ; } return ans; }
求最小因子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const int maxn = 1e7 +5 ;int isprime[maxn/3 ] = {0 },num_prime = 0 ;int MinFactor[maxn];inline void FindMinFactor (int n) { MinFactor[1 ] = 1 ; for (int i = 2 ; i < n; i++){ if (!MinFactor[i]){ isprime[num_prime++]=i; MinFactor[i] = i; } for (int j = 0 ; i * isprime[j] < n && j < num_prime; j++){ Minfactor[i * isprime[j]] = isprime[j]; if (!(i % isprime[j])) break ; } } }
调和级数求和 当n很大时,f(n)≈ln(n)+C+1/2*n
其中C≈0.57721566490153286060651209
当n不是很大时,打表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const int maxn = 1e6 +5 ;const double c = 0.57721566490153286060651209 ;double ans[1000006 ];inline void init (void ) { double a = 0 ; for (int i = 1 ;i < maxn;i++){ a += (1.0 / (double )i); ans[i] = a; } } signed main (void ) { ll t; read (t); init (); for (ll Case = 1 ;Case <= t;Case++){ ll n; read (n); double a; if (n < maxn){ a = ans[n]; }else { a = log (n) + c + (1.0 ) / (2 * n); } printf ("Case %lld: %.10lf\n" ,Case, a); } return 0 ; }
康托展开 给定一个1~n
的排列,求该排列在1~n
的全排列中,按字典序排名多少位。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int num[100 ];int factorial[100 ]={1 ,1 ,2 ,6 ,24 ,120 ,720 ,5040 ,40320 ,362880 ,3628800 };inline int cantor (int n, int num[100 ]) { int X=0 ; for (int i=1 ;i<n;i++){ int a_i=0 ; for (int j=i+1 ;j<=n;j++){ if (num[i]>num[j]) a_i++; } X+=a_i*factorial[n-i]; } X=X+1 ; return X; }
逆康托展开 给定一个1~n
的排列,求在该排列在1~n
的全排列中,按字典序第k位所对应的排列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int factorial[100 ]={1 ,1 ,2 ,6 ,24 ,120 ,720 ,5040 ,40320 ,362880 ,3628800 };void decantor (int x,int n) { vector<int > v; vector<int > ans; for (int i=1 ;i<=n;i++) v.push_back (i); for (int i=m;i>=1 ;i--){ int r=x%factorial[i-1 ]; int t=x/factorial[i-1 ]; x=r; sort (v.begin (),v.end ()); ans.push_back (v[t]); v.erase (v.begin ()+t); } }
同余定理
(a+b)%c=(a%c+b%c)%c;
(a*b)%c=(a%c*b%c)%c;
求逆元 加减乘与模运算的顺序交换不会影响结果,但是除法不行。有的题目要求结果mod一个大质数,如果原本的结果中有除法,比如除以a,那就可以乘以a的逆元替代。
法一:扩展欧几里得
1 2 3 4 5 6 7 8 9 10 11 12 13 int x, y;int extgcd (int a, int b, int &x, int &y) { if (b == 0 ){ x = 1 ; y = 0 ; return a; } int gcd = exgcd (b, a % b, x, y); int tmp = x; x = y; y = tmp - (a/b) * y; return gcd; }
组合数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const int maxn = 200000 + 5 ;const int mod = (int )1e9 + 7 ;ll F[maxn], Finv[maxn], inv[maxn]; inline void comb_init () { inv[1 ] = 1 ; for (ll i = 2 ; i < maxn; i ++){ inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod; } F[0 ] = Finv[0 ] = 1 ; for (ll i = 1 ; i < maxn; i ++){ F[i] = F[i-1 ] * 1ll * i % mod; Finv[i] = Finv[i-1 ] * 1ll * inv[i] % mod; } } inline ll comb (ll n, ll m) { if (m < 0 || m > n) return 0 ; return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod; }
快速幂 1 2 3 4 5 6 7 8 9 10 11 inline ll PowerMod (ll a, ll b, ll c) { ll ans = 1 ; a = a % c; while (b>0 ){ if (b % 2 == 1 ) ans = ((ans % c) * (a % c)) % c; b = b/2 ; a = (a * a) % c; } return ans; }
快速幂取前k位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 inline double check (double x, double mod) { while (x >= mod){ x /= 10.0 ; } return x; } inline ll PowerMod (ll a, ll b, ll k) { double a1 = (double )a; double ans = 1.0 ; double mod = 1.0 ; for (ll i = 0 ;i < k;i++) mod*=10.0 ; while (b>0 ){ if (b % 2 == 1 ){ ans = ans * a1; ans = check (ans, mod); } b = b/2 ; a1 = (a1 * a1); a1 = check (a1, mod); } return (ll)ans; }
三角形面积 1 2 3 4 5 6 double Heron (double a, double b, double c) { double p,S; p=(a+b+c)/2 ; S=sqrt (p*(p-a)*(p-b)*(p-c)); return S; }
三点顺序 1 2 3 4 5 6 7 8 9 int func (int x1, int y1, int x2, int y2, int x3, int y3) { if (x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0 && x3 == 0 && y3 == 0 )break ; int A = x2 - x1; int B = y2 - y1; int C = x3 - x1; int D = y3 - y1; if (A*D - B*C > 0 ) return 0 ; else return 1 ; }
大数操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 const int MAXN = 9999 ; const int MAXSIZE = 10 ; const int DLEN = 4 ;class BigNum { private : int a[500 ]; int len; public : BigNum (){ len = 1 ;memset (a,0 ,sizeof (a)); } BigNum (const int ); BigNum (const char *); BigNum (const BigNum &); BigNum &operator =(const BigNum &); friend istream& operator >>(istream&, BigNum&); friend ostream& operator <<(ostream&, BigNum&); BigNum operator +(const BigNum &) const ; BigNum operator -(const BigNum &) const ; BigNum operator *(const BigNum &) const ; BigNum operator /(const int &) const ; BigNum operator ^(const int &) const ; int operator %(const int &) const ; bool operator >(const BigNum & T)const ; bool operator >(const int & t)const ; void print () ; }; BigNum::BigNum (const int b) { int c,d = b; len = 0 ; memset (a,0 ,sizeof (a)); while (d > MAXN) { c = d - (d / (MAXN + 1 )) * (MAXN + 1 ); d = d / (MAXN + 1 ); a[len++] = c; } a[len++] = d; } BigNum::BigNum (const char *s) { int t,k,index,l,i; memset (a,0 ,sizeof (a)); l=strlen (s); len=l/DLEN; if (l%DLEN) len++; index=0 ; for (i=l-1 ;i>=0 ;i-=DLEN) { t=0 ; k=i-DLEN+1 ; if (k<0 ) k=0 ; for (int j=k;j<=i;j++) t=t*10 +s[j]-'0' ; a[index++]=t; } } BigNum::BigNum (const BigNum & T) : len (T.len) { int i; memset (a,0 ,sizeof (a)); for (i = 0 ; i < len ; i++) a[i] = T.a[i]; } BigNum & BigNum::operator =(const BigNum & n) { int i; len = n.len; memset (a,0 ,sizeof (a)); for (i = 0 ; i < len ; i++) a[i] = n.a[i]; return *this ; } istream& operator >>(istream & in, BigNum & b) { char ch[MAXSIZE * 4 ]; int i = -1 ; in>>ch; int l=strlen (ch); int count=0 ,sum=0 ; for (i=l-1 ;i>=0 ;) { sum = 0 ; int t=1 ; for (int j=0 ;j<4 &&i>=0 ;j++,i--,t*=10 ) { sum+=(ch[i]-'0' )*t; } b.a[count]=sum; count++; } b.len =count++; return in; } ostream& operator <<(ostream& out, BigNum& b) { int i; cout << b.a[b.len - 1 ]; for (i = b.len - 2 ; i >= 0 ; i--) { cout.width (DLEN); cout.fill ('0' ); cout << b.a[i]; } return out; } BigNum BigNum::operator +(const BigNum & T) const { BigNum t (*this ) ; int i,big; big = T.len > len ? T.len : len; for (i = 0 ; i < big ; i++) { t.a[i] +=T.a[i]; if (t.a[i] > MAXN) { t.a[i + 1 ]++; t.a[i] -=MAXN+1 ; } } if (t.a[big] != 0 ) t.len = big + 1 ; else t.len = big; return t; } BigNum BigNum::operator -(const BigNum & T) const { int i,j,big; bool flag; BigNum t1,t2; if (*this >T) { t1=*this ; t2=T; flag=0 ; } else { t1=T; t2=*this ; flag=1 ; } big=t1.len; for (i = 0 ; i < big ; i++) { if (t1.a[i] < t2.a[i]) { j = i + 1 ; while (t1.a[j] == 0 ) j++; t1.a[j--]--; while (j > i) t1.a[j--] += MAXN; t1.a[i] += MAXN + 1 - t2.a[i]; } else t1.a[i] -= t2.a[i]; } t1.len = big; while (t1.a[len - 1 ] == 0 && t1.len > 1 ) { t1.len--; big--; } if (flag) t1.a[big-1 ]=0 -t1.a[big-1 ]; return t1; } BigNum BigNum::operator *(const BigNum & T) const { BigNum ret; int i,j,up; int temp,temp1; for (i = 0 ; i < len ; i++) { up = 0 ; for (j = 0 ; j < T.len ; j++) { temp = a[i] * T.a[j] + ret.a[i + j] + up; if (temp > MAXN) { temp1 = temp - temp / (MAXN + 1 ) * (MAXN + 1 ); up = temp / (MAXN + 1 ); ret.a[i + j] = temp1; } else { up = 0 ; ret.a[i + j] = temp; } } if (up != 0 ) ret.a[i + j] = up; } ret.len = i + j; while (ret.a[ret.len - 1 ] == 0 && ret.len > 1 ) ret.len--; return ret; } BigNum BigNum::operator /(const int & b) const { BigNum ret; int i,down = 0 ; for (i = len - 1 ; i >= 0 ; i--) { ret.a[i] = (a[i] + down * (MAXN + 1 )) / b; down = a[i] + down * (MAXN + 1 ) - ret.a[i] * b; } ret.len = len; while (ret.a[ret.len - 1 ] == 0 && ret.len > 1 ) ret.len--; return ret; } int BigNum::operator %(const int & b) const { int i,d=0 ; for (i = len-1 ; i>=0 ; i--) { d = ((d * (MAXN+1 ))% b + a[i])% b; } return d; } BigNum BigNum::operator ^(const int & n) const { BigNum t,ret (1 ); int i; if (n<0 ) exit (-1 ); if (n==0 ) return 1 ; if (n==1 ) return *this ; int m=n; while (m>1 ) { t=*this ; for ( i=1 ;i<<1 <=m;i<<=1 ) { t=t*t; } m-=i; ret=ret*t; if (m==1 ) ret=ret*(*this ); } return ret; } bool BigNum::operator >(const BigNum & T) const { int ln; if (len > T.len) return true ; else if (len == T.len) { ln = len - 1 ; while (a[ln] == T.a[ln] && ln >= 0 ) ln--; if (ln >= 0 && a[ln] > T.a[ln]) return true ; else return false ; } else return false ; } bool BigNum::operator >(const int & t) const { BigNum b (t) ; return *this >b; } void BigNum::print () { int i; cout << a[len - 1 ]; for (i = len - 2 ; i >= 0 ; i--) { cout.width (DLEN); cout.fill ('0' ); cout << a[i]; } cout << endl; }