サイズ: 14226
コメント:
|
サイズ: 14455
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 15: | 行 15: |
{{{#!cpp | {{{#!highlight cpp |
行 38: | 行 38: |
{{{#!cpp | {{{#!highlight cpp |
行 62: | 行 62: |
{{{#!cpp | {{{#!highlight cpp |
行 71: | 行 71: |
{{{#!cpp | {{{#!highlight cpp |
行 82: | 行 82: |
enum LPposit { P_CD = -2, P_CW = -1, P_OS = 0, P_CCW = 1, P_D = 2}; | |
行 95: | 行 96: |
{{{#!cpp | {{{#!highlight cpp |
行 115: | 行 116: |
{{{#!cpp | {{{#!highlight cpp |
行 126: | 行 127: |
{{{#!cpp | {{{#!highlight cpp |
行 136: | 行 137: |
{{{#!cpp | {{{#!highlight cpp |
行 149: | 行 150: |
{{{#!cpp | {{{#!highlight cpp |
行 171: | 行 172: |
{{{#!cpp | {{{#!highlight cpp |
行 226: | 行 227: |
{{{#!cpp | {{{#!highlight cpp |
行 263: | 行 264: |
{{{#!cpp | {{{#!highlight cpp |
行 301: | 行 302: |
{{{#!cpp | {{{#!highlight cpp |
行 319: | 行 320: |
{{{#!cpp | {{{#!highlight cpp |
行 356: | 行 357: |
{{{#!cpp | {{{#!highlight cpp |
行 434: | 行 435: |
{{{#!cpp | {{{#!highlight cpp |
++w++ ICPCライブラリ
++w++(amylase, y3eadgbe, atetubou(is2012))で使用する ICPC ライブラリ置き場。 (last updated: 11/8 20:42)
- TODO
- 線型計画を二段階単体法にする。
- 幾何(線分アレンジメント)
- 文字列(KMP method, Aho-Corasick algorithm)
- (ここには載せないが、蟻本から最大流・最小費用流・拡張ユークリッド・連立線型合同式を持っていく)
- 余裕があれば有名問題を増やす。
- グラフ彩色
目次
テンプレート
1 #include <iostream>
2 #include <vector>
3 #include <map>
4 #include <algorithm>
5 #include <queue>
6 #include <cstring>
7 #include <complex>
8
9 using namespace std;
10
11 #define rep(i,n) for(int i=0;i<n;++i)
12 #define pb(a) push_back(a)
13 #define mp(a,b) make_pair(a,b)
14 #define F first
15 #define S second
16 #define SZ(a) (int)((a).size())
17
- だいたいコードの先頭にあると考えておいてね。
幾何
基本要素
1 // primitives
2 typedef long double Real;
3 typedef complex<Real> Pt;
4 typedef pair<Pt, Pt> Line;
5 typedef pair<Pt, Real> Circle;
6 typedef vector<Pt> Poly;
7
8 Real eps = 1e-9;
9
10 inline istream& operator>>(istream& s, Pt& p) {return s >> p.real() >> p.imag();}
11 inline bool near(const Pt& p, const Pt& q){return abs(p - q) < eps;}
- Real : long double, double の切り替え用に。
- Pt : 点もしくはベクトル。abs(x) で長さ。arg(x) で偏角[-pi, +pi]。a + bi = pt(a, b)
- Line : 線分・直線。通る2点(線分では両端)。
- Circle : 円。中心点と半径。
- Poly : 多角形。反時計回りに頂点を持つ。
- eps : 許容誤差。問題によって値を修正する。
operator>> : (x座標) (y座標) と来た時に一発で読み取る。
- near : 誤差を許容して同じ点かどうか見るよ。
内積・外積の大きさ
- dot : a, b の内積。射影を取ったりするときに使う。
- cross : a, b が張る平行四辺形の面積。三角形の面積とか。a, b を通る直線上の点 x が cross(x, b) = cross(a, b) を満たすことから、abの法線を軸としたパラメータとの解釈もある。
3点の位置関係
1 // ccw_b : old version of ccw.
2 inline Real ccw_b(const Pt& p, const Pt& q, const Pt& r) {return cross(q - p, r - p);}
3
4 /* ccw :
5 CD : counter direction
6 CW : clock wise
7 OS : on segment
8 CCW : counter clock wise
9 D : direction
10 */
11 enum LPposit { P_CD = -2, P_CW = -1, P_OS = 0, P_CCW = 1, P_D = 2};
12 LPposit ccw(const Pt& p, const Pt& q, const Pt& r) {
13 Real c = ccw_b(p, q, r);
14 if (c < -eps) return P_CW;
15 if (c > eps) return P_CCW;
16 if (dot(q - p, r - p) < -eps) return P_CD;
17 if (dot(p - q, r - q) < -eps) return P_D;
18 return P_OS;
19 }
- ccw_b : 上で述べた cross のパラメータ解釈での値を計算。
- ccw : コメント参照!
点と直線の距離
1 inline Real Sabs(const Line& l) {return abs(l.first - l.second); }
2 inline Real LPdist(const Line& l, const Pt& p) {return abs(ccw_b(l.first, l.second, p)) / Sabs(l); }
3 inline Real SPdist(const Line& l, const Pt& p) {
4 if ((Labs(l) > abs(l.first - p) && Labs(l) > abs(l.second - p)) ||
5 cos(arg(p - l.first) - arg(p - l.second)) > 0){
6
7 return LPdist(l, p);
8 }
9
10 return min(abs(p - l.first), abs(p - l.second));
11 }
- Sabs : 線分の長さ。
- LPdist : 点と直線の距離。
- SPdist : 点と線分の距離。
- L : line, S : segment, P : point
線分の交差判定
- 線分 p と q が交差するかどうか。
直線の交点
多角形の面積
- 多角形の面積。凸性は仮定しない。O(n)。
- 時計回りの時は面積が -1 倍される。abs 取ろう。
円と直線の交点
1 vector<pt> circle_line_intersect(line l,circle c){
2 vector<pt> ret;
3 LD di = dist(l,c.first);
4 LD r=c.second;
5 if(di+EPS > r) return ret;
6 pt v=(l.second-l.first);
7 v/=abs(v);
8 pt rv=v*pt(0,1);
9 rv*=di;
10 if(dist(l,c.first+rv) > di+EPS) rv = -rv;
11 v*=sqrt(r*r-di*di);
12 ret.push_back(c.first+rv-v);
13 ret.push_back(c.first+rv+v);
14 return ret;
15 }
- 円と直線の交点を求める。
- 円が直線と接しない場合はemptyを返し、それ以外は取り敢えず二つの要素を持つvectorを返す。
円の共通接線
1 vector<line> contact(circle p, circle q){
2 vector<line> ret;
3 if(p.second < q.second) swap(p, q);
4 long double d = abs(p.first - q.first);
5 pt n = q.first - p.first;
6 n /= abs(n);
7
8 if(d + eps < abs(p.second - q.second)){
9 ret.clear();
10 } else if(eq(d, abs(p.second - q.second))){
11 pt t, u;
12 t = p.first + p.second * n;
13 u = t + n * pt(0, 1);
14 ret.push_back(make_pair(t, u));
15 } else {
16 if(!eq(p.second, q.second)){
17 pt t = p.first + (p.second * d / (p.second - q.second)) * n;
18 long double theta = asin((p.second - q.second) / d);
19 pt u = n * pt(cos(theta), sin(theta));
20 pt v = n * pt(cos(-theta), sin(-theta));
21 u += t;
22 v += t;
23 ret.push_back(make_pair(t, u));
24 ret.push_back(make_pair(t, v));
25 } else {
26 pt t = p.first + n * pt(0, 1) * p.second;
27 pt u = p.first - n * pt(0, 1) * p.second;
28 ret.push_back(make_pair(t, t+n));
29 ret.push_back(make_pair(u, u+n));
30 }
31
32 if(eq(d, p.second + q.second)){
33 pt t, u;
34 t = p.first + p.second * n;
35 u = t + n * pt(0, 1);
36 ret.push_back(make_pair(t, u));
37 } else if(d > p.second + q.second){
38 pt t = p.first + (p.second * d / (p.second + q.second)) * n;
39 long double theta = asin((p.second + q.second) / d);
40 pt u = n * pt(cos(theta), sin(theta));
41 pt v = n * pt(cos(-theta), sin(-theta));
42 u += t;
43 v += t;
44 ret.push_back(make_pair(t, u));
45 ret.push_back(make_pair(t, v));
46 }
47 }
48 return ret;
49 }
vector<line> の各要素が接線。
凸包
1 // convex-hull
2 // return minimum convex polygon that contains every point in vs.
3 // depend on ccw
4 namespace std{
5 bool operator<(const Pt& a, const Pt& b) {
6 return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
7 }
8 }
9
10 Poly convexHull(vector<Pt> ps) {
11 int n = ps.size();
12 sort(ps.begin(), ps.end());
13
14 Poly ret(2 * n);
15 int m = 0;
16 for (int i = 0; i < n; i++) {
17 while (m >= 2 && ccw(ret[m-2], ret[m-1], ps[i]) < 0) m--;
18 ret[m++] = ps[i];
19 }
20
21 int t = m;
22 for (int i = n-2; i >= 0; i--) {
23 while (m >= t && ccw(ret[m-2], ret[m-1], ps[i]) < 0) m--;
24 ret[m++] = ps[i];
25 }
26
27 ret.resize(m - 1);
28 return ret;
29 }
- Pt の座標軸ソートもついてる。
- convexHull : ps に含まれる点をすべて含む最小の凸多角形を返す。spaghetthi source を参考にしたよ。
数論
ミラー・ラビン素数判定法
1 long long powmod(long long x, long long p, long long m){
2 if(p == 0) return 1;
3 long long rt = powmod(x, p/2, m);
4 if(p % 2 == 0){
5 return rt * rt % m;
6 } else {
7 return (rt * rt % m) * x % m;
8 }
9 }
10
11 int miller_test[9] = {2,3,5,7,11,13,17,19,23};
12 bool isprime(long long n){
13 if(n <= ISPR_MAX) return !isnpr[n];
14
15 long long d = n-1, s = 0;
16 while(d%2 == 0){
17 d /= 2;
18 s++;
19 }
20
21 for(int i=0; i<9; i++){
22 bool iscomp = true;
23 li x = powmod(miller_test[i], d, n);
24 iscomp = iscomp && (x % n != 1);
25
26 for(int r=0; r<s; r++){
27 iscomp = iscomp && (x % n != n-1);
28 x = x * x % n;
29 }
30 if(iscomp) return false;
31 }
32
33 return true;
34 }
ポラード・ロー素因数分解法
数学
行列乗算
1 typedef vector<vector<li> > matrix;
2 const li mod = 1000000007;
3
4 matrix ident(const int& n) {
5 matrix ret(n, vi(n, 0));
6 rep(i, n) ret[i][i] = 1;
7 return ret;
8 }
9
10 matrix matadd(const matrix& p, const matrix& q) {
11 int n = p.size(), m = p[0].size();
12 matrix ret = p;
13 rep(i, n) rep(j, m) ret[i][j] = (p[i][j] + q[i][j]) % mod;
14 return ret;
15 }
16
17 matrix matmul(const matrix& p, const matrix& q) {
18 int n = p.size(), m = q[0].size(), l = p[0].size();
19 matrix ret = matrix(n, vi(m, 0));
20 rep(i, n) rep(j, m) rep(k, l) ret[i][j] = (ret[i][j] + p[i][k] * q[k][j] % mod) % mod;
21 return ret;
22 }
23
24 matrix matpow(const matrix& p, const li& x) {
25 if (x == 0) return ident(p.size());
26 if (x == 1) return p;
27 matrix ret = matpow(p, x / 2);
28 ret = matmul(ret, ret);
29 if (x % 2) ret = matmul(ret, p);
30 return ret;
31 }
- 2次元配列で行列を表現。エラーチェックなし。mod とってます。
畳み込み
1 typedef double Real;
2 typedef complex<Real> Complex;
3
4 vector<Complex> fastFourierTransform(const vector<Complex>& x) {
5 if (__builtin_popcount(x.size()) > 1) {
6 cerr << "fastFourierTransform: x.size() should be power of 2." << endl;
7 return x;
8 }
9
10 const int n = x.size();
11 if (n == 1) {
12 return x;
13 }
14
15 vector<Complex> even(n / 2), odd(n / 2), ret(n);
16 for (int i = 0; i < n; ++i) {
17 if (i % 2 == 0) {
18 even[i / 2] = x[i];
19 } else {
20 odd[i / 2] = x[i];
21 }
22 }
23
24 even = fastFourierTransform(even);
25 odd = fastFourierTransform(odd);
26
27 for (int i = 0; i < n; ++i) {
28 int j = i % (n / 2);
29 ret[i] = even[j] + odd[j] * exp(Complex(0, -2 * M_PI * i / n));
30 }
31
32 return ret;
33 }
34
35 vector<Complex> inverseFastFourierTransform(vector<Complex> x) {
36 const int n = x.size();
37 for (int i = 0; i < n; ++i) {
38 x[i] = conj(x[i]);
39 }
40 x = fastFourierTransform(x);
41 for (int i = 0; i < n; ++i) {
42 x[i] = conj(x[i]) / Complex(n);
43 }
44 return x;
45 }
46
47 int conv_minpow2(int x) {
48 int ret = 1;
49 while (ret < x) ret <<= 1;
50 return ret;
51 }
52
53 vector<Complex> convolution(vector<Complex> x,
54 vector<Complex> y) {
55 int l = 2 * max(conv_minpow2(x.size()), conv_minpow2(y.size()));
56 x.resize(l);
57 y.resize(l);
58
59 x = fastFourierTransform(x);
60 y = fastFourierTransform(y);
61
62 vector<Complex> ret(l);
63 for (int i = 0; i < l; i++) {
64 ret[i] = x[i] * y[i];
65 }
66
67 ret = inverseFastFourierTransform(ret);
68 while (not ret.empty() && ret.back() == Complex(0)) ret.pop_back();
69 return ret;
70 }
- 高速フーリエ変換による畳み込み演算。O(n log n)。
- 多項式の掛け算がナイーブにやるとO(n^2)だが畳込みを使うと計算量が落ちたり。
有名問題
線型計画法
1 // linear programming by simplex method
2 // solve maximize(cx) s.t. Ax <= a
3 // if not bounded, return -1.
4 double simplex(vector<double>& c,
5 vector<vector<double> >& A,
6 vector<double>& a) {
7 // introduce slack variable
8 int n = c.size(), m = a.size(), dim = n + m;
9 vector<int> N(n), B(m);
10 for (int i = 0; i < n; ++i) N[i] = i;
11 for (int i = 0; i < m; ++i) {
12 B[i] = i + n;
13 c.push_back(0);
14 for (int j = 0; j < n; j++) A[i][j] *= -1;
15 for (int j = 0; j < m; j++) A[i].push_back(0);
16 }
17
18 double ans = 0;
19
20 while (true) {
21 // check optimized or not
22 int s = -1;
23 for (int i = 0; i < n; i++) if (c[N[i]] > 0) s = N[i];
24 if (s < 0) break;
25
26 // check bounded or not
27 double bound = 1e300;
28 int r = -1;
29 for (int i = 0; i < m; i++) {
30 if (A[i][N[s]] < 0) {
31 double nbound = -a[i] / A[i][N[s]];
32 if (nbound < bound) {
33 bound = nbound;
34 r = i;
35 }
36 }
37 }
38
39 if (r < 0) return -1;
40
41 // pivotting
42 for (int i = 0; i < dim; i++) if (i != N[s]) A[r][i] /= -A[r][N[s]];
43 a[r] /= -A[r][N[s]];
44 A[r][B[r]] = 1.0 / A[r][N[s]];
45 A[r][N[s]] = 0;
46
47 for (int i = 0; i < m; i++) {
48 if (i == r) continue;
49
50 for (int j = 0; j < dim; j++) if (j != N[s]) A[i][j] += A[i][N[s]] * A[r][j];
51 a[i] += A[i][N[s]] * a[r];
52 A[i][N[s]] = 0;
53 }
54
55 ans += c[N[s]] * a[r];
56 for (int i = 0; i < dim; i++) if (i != N[s]) c[i] += c[N[s]] * A[r][i];
57 c[N[s]] = 0;
58
59 swap(N[s], B[r]);
60 }
61
62 return ans;
63 }
simplex(c, A, a) : maximize cx, where Ax <= a, x >= 0 なる線型計画問題を単体法で解く。
- x = 0 が実行可能解であることを仮定している(つまり、TODOとして二段階単体法に改善することがあげられる)。
- 発散する場合には -1 を返す。有限な最適解は必ず正になっているはずなので、正負を見れば発散したかどうかがわかる。