├── Makefile ├── README.md ├── UTF8-UCS2 ├── datastructure.tex ├── datastructure ├── .directory ├── chairmantree.tex ├── dynamictree.tex ├── kthtree.tex ├── lct.tex ├── splay.tex ├── treap.tex └── treearray.tex ├── dp.tex ├── dp ├── lis2.tex ├── rmq.tex ├── scdp.tex └── slope.tex ├── geometric.tex ├── geometric ├── .directory ├── 3D.tex ├── 3DCH.tex ├── GS.tex ├── HPI.tex ├── KDtree.tex ├── RotatingCalipers.tex ├── areaofcircles.tex ├── base.tex ├── center.tex ├── circle.tex ├── circleandpoly.tex ├── eps.tex ├── howmanystars.tex ├── intersectionbetweenlineandconvexhull.tex ├── matrix.tex ├── nearsetpoints.tex ├── notice.tex ├── pointtopoly.tex └── trangle.tex ├── graph.tex ├── graph ├── CountSpanningTrees.tex ├── bc.tex ├── bestmst.tex ├── clique.tex ├── cutbridge.tex ├── dijkstra.tex ├── edmonds.tex ├── euler.tex ├── km.tex ├── kthpath.tex ├── lca.tex ├── marry.tex ├── match.tex ├── match2.tex ├── mcmf.tex ├── networksimplex.tex ├── planar.tex ├── sap.tex ├── sc.tex ├── sw.tex └── zhuliu.tex ├── math.tex ├── math ├── BSGS.tex ├── MLES.tex ├── calc.tex ├── cantor.tex ├── combination.tex ├── euler.tex ├── exgcd.tex ├── fermat.tex ├── fft.tex ├── getfactor.tex ├── guess.tex ├── inv.tex ├── lucus.tex ├── matrix.tex ├── others.tex ├── partition.tex ├── prime.tex ├── primeroot.tex ├── simp.tex └── simplex.tex ├── notice.tex ├── others.tex ├── others ├── bigint.tex ├── bit.tex ├── hashmap.tex ├── java.tex ├── others.tex ├── readint.tex └── stl.tex ├── search.tex ├── search └── dlx.tex ├── string.tex ├── string ├── ACautomaton.tex ├── KMP.tex ├── Manacher.tex ├── eKMP.tex ├── ls.tex ├── palindromes.tex ├── smallestrepresention.tex ├── suffixarrays.tex └── suffixtree.tex ├── template.tex ├── template_xelatex.tex └── todolist.tex /Makefile: -------------------------------------------------------------------------------- 1 | latex: template.pdf 2 | mv template.pdf pdf/template.pdf 3 | rm -f *.dvi 4 | 5 | xelatex: template_xelatex.pdf 6 | mv template_xelatex.pdf pdf/template_xelatex.pdf 7 | rm -f *.dvi 8 | 9 | all: template.pdf template_xelatex.pdf 10 | mv template.pdf pdf/template.pdf 11 | mv template_xelatex.pdf pdf/template_xelatex.pdf 12 | rm -f *.dvi 13 | 14 | template.pdf: template.dvi 15 | dvipdfmx $< 16 | 17 | template.dvi: template.tex 18 | latex $< 19 | latex $< 20 | 21 | template_xelatex.pdf: template_xelatex.tex 22 | xelatex $< 23 | xelatex $< 24 | 25 | clean: 26 | rm -f *.pdf 27 | rm -f *.dvi 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # My ACMICPCTemplate # 2 | 不好玩 3 | 4 | ## Compling ## 5 | make 6 | 7 | ## Notice ## 8 | template.pdf是用latex+dvipdfmx生成的;template_xelatex.pdf是用xelatex生成的,主要是考虑到代码用DejaVu Sans Mono做打印字体的话某些容易混的细节可以被很好的分辨出来(例如l和1) -------------------------------------------------------------------------------- /datastructure.tex: -------------------------------------------------------------------------------- 1 | \section{数据结构} 2 | \input datastructure/splay.tex 3 | \input datastructure/dynamictree.tex 4 | \input datastructure/chairmantree.tex 5 | \input datastructure/treap.tex 6 | \input datastructure/lct.tex 7 | \input datastructure/kthtree.tex 8 | \input datastructure/treearray.tex -------------------------------------------------------------------------------- /datastructure/.directory: -------------------------------------------------------------------------------- 1 | [Dolphin] 2 | AdditionalInfo=Details_Size,Details_Date,Details_Type,CustomizedDetails 3 | SortOrder=1 4 | Sorting=6 5 | Timestamp=2012,9,29,13,32,47 6 | ViewMode=1 7 | -------------------------------------------------------------------------------- /datastructure/chairmantree.tex: -------------------------------------------------------------------------------- 1 | \subsection{可持久化线段树} 2 | 区间第$k$小数,内存压缩版,POJ2014。 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int MAXN=100000,MAXM=100000; 9 | 10 | struct node 11 | { 12 | node *l,*r; 13 | int sum; 14 | }tree[MAXN*4+MAXM*20]; 15 | 16 | int N; 17 | node *newnode() 18 | { 19 | tree[N].l=tree[N].r=NULL; 20 | tree[N].sum=0; 21 | return &tree[N++]; 22 | } 23 | node *newnode(node *x) 24 | { 25 | tree[N].l=x->l; 26 | tree[N].r=x->r; 27 | tree[N].sum=x->sum; 28 | return &tree[N++]; 29 | } 30 | node *build(int l,int r) 31 | { 32 | node *x=newnode(); 33 | if (l>1; 36 | x->l=build(l,mid); 37 | x->r=build(mid+1,r); 38 | x->sum=x->l->sum+x->r->sum; 39 | } 40 | else 41 | x->sum=0; 42 | return x; 43 | } 44 | node *update(node *x,int l,int r,int p,int v) 45 | { 46 | if (l>1; 49 | node *nx=newnode(x); 50 | if (p<=mid) 51 | { 52 | node *ret=update(x->l,l,mid,p,v); 53 | nx->l=ret; 54 | } 55 | else 56 | { 57 | node *ret=update(x->r,mid+1,r,p,v); 58 | nx->r=ret; 59 | } 60 | nx->sum=nx->l->sum+nx->r->sum; 61 | return nx; 62 | } 63 | else 64 | { 65 | node *nx=newnode(x); 66 | nx->sum+=v; 67 | return nx; 68 | } 69 | } 70 | int query(node *x1,node *x2,int l,int r,int k) 71 | { 72 | if (l>1; 75 | int lsum=x2->l->sum-x1->l->sum; 76 | if (lsum>=k) 77 | return query(x1->l,x2->l,l,mid,k); 78 | else 79 | return query(x1->r,x2->r,mid+1,r,k-lsum); 80 | } 81 | else 82 | return l; 83 | } 84 | char s[10]; 85 | node *root[MAXM+1]; 86 | int a[MAXN],b[MAXN]; 87 | int init(int n) 88 | { 89 | for (int i=0;i>1; 99 | if (b[mid]>=a[i]) 100 | r=mid; 101 | else 102 | l=mid+1; 103 | } 104 | a[i]=l; 105 | } 106 | return tn; 107 | } 108 | int main() 109 | { 110 | int cas=1,n; 111 | while (scanf("%d",&n)!=EOF) 112 | { 113 | printf("Case %d:\n",cas++); 114 | for (int i=0;i>1)]); 128 | } 129 | } 130 | return 0; 131 | } 132 | \end{lstlisting} -------------------------------------------------------------------------------- /datastructure/dynamictree.tex: -------------------------------------------------------------------------------- 1 | \subsection{动态树} 2 | 懒标记是否及时Pushdown了?\\ 3 | 修改之后有没有及时Pushup?\\ 4 | \subsubsection{维护点权} 5 | 查询链上的最长字段和\\ 6 | GetRoute是用换根写的\\ 7 | \begin{lstlisting}[language=c++] 8 | const int MaxN = 110000; 9 | 10 | struct Node 11 | { 12 | int size, key; 13 | bool rev; 14 | 15 | // bool same; 16 | // int lsum, rsum, sum, maxsum, sa; 17 | 18 | Node *c[2]; 19 | Node *p; 20 | } mem[MaxN], *cur, *nil, *pos[MaxN]; 21 | 22 | Node *newNode(int v, Node *p) 23 | { 24 | cur->c[0] = cur->c[1] = nil, cur->p = p; 25 | cur->size = 1; 26 | cur->key = v; 27 | cur->rev = false; 28 | 29 | // cur->same = false; 30 | // cur->sa = 0; 31 | // cur->lsum = cur->rsum = cur->maxsum = 0; 32 | // cur->sum = v; 33 | 34 | return cur++; 35 | } 36 | 37 | void Init() 38 | { 39 | cur = mem; 40 | nil = newNode(0, cur); 41 | nil->size = 0; 42 | } 43 | 44 | struct SplayTree 45 | { 46 | void Pushup(Node *x) 47 | { 48 | if (x == nil) return; 49 | Pushdown(x); Pushdown(x->c[0]); Pushdown(x->c[1]); 50 | x->size = x->c[0]->size + x->c[1]->size + 1; 51 | 52 | // x->sum = x->c[0]->sum + x->c[1]->sum + x->key; 53 | // x->lsum = max(x->c[0]->lsum, 54 | // x->c[0]->sum + x->key + max(0, x->c[1]->lsum)); 55 | // x->rsum = max(x->c[1]->rsum, 56 | // x->c[1]->sum + x->key + max(0, x->c[0]->rsum)); 57 | // x->maxsum = max(max(x->c[0]->maxsum, x->c[1]->maxsum), 58 | // x->key + max(0, x->c[0]->rsum) + max(0, x->c[1]->lsum)); 59 | 60 | } 61 | void Pushdown(Node *x) 62 | { 63 | if (x == nil) return; 64 | if (x->rev) 65 | { 66 | x->rev = 0; 67 | x->c[0]->rev ^= 1; 68 | x->c[1]->rev ^= 1; 69 | swap(x->c[0], x->c[1]); 70 | //注意修改与位置有关的量 71 | // swap(x->lsum,x->rsum); 72 | } 73 | 74 | // if (x->same) 75 | // { 76 | // x->same = false; 77 | // x->key = x->sa; 78 | // x->sum = x->sa * x->size; 79 | // x->lsum = x->rsum = x->maxsum = max(0, x->sum); 80 | // if (x->c[0] != nil) 81 | // x->c[0]->same = true, x->c[0]->sa = x->sa; 82 | // if (x->c[1] != nil) 83 | // x->c[1]->same = true, x->c[1]->sa = x->sa; 84 | // } 85 | } 86 | bool isRoot(Node *x) 87 | { 88 | return (x == nil) || (x->p->c[0] != x && x->p->c[1] != x); 89 | } 90 | void Rotate(Node *x, int f) 91 | { 92 | if (isRoot(x)) return; 93 | Node *y = x->p; 94 | y->c[f ^ 1] = x->c[f], x->p = y->p; 95 | if (x->c[f] != nil) 96 | x->c[f]->p = y; 97 | if (y != nil) 98 | { 99 | if (y == y->p->c[1]) 100 | y->p->c[1] = x; 101 | else if (y == y->p->c[0]) 102 | y->p->c[0] = x; 103 | } 104 | x->c[f] = y, y->p = x; 105 | Pushup(y); 106 | } 107 | void Splay(Node *x) 108 | { 109 | static Node *stack[MaxN]; 110 | int top = 0; 111 | stack[top++] = x; 112 | for (Node *y = x; !isRoot(y); y = y->p) 113 | stack[top++] = y->p; 114 | while (top) 115 | Pushdown(stack[--top]); 116 | 117 | while (!isRoot(x)) 118 | { 119 | Node *y = x->p; 120 | if (isRoot(y)) 121 | Rotate(x, x == y->c[0]); 122 | else 123 | { 124 | int fd = y->p->c[0] == y; 125 | if (y->c[fd] == x) 126 | Rotate(x, fd ^ 1), Rotate(x, fd); 127 | else 128 | Rotate(y, fd), Rotate(x, fd); 129 | } 130 | } 131 | Pushup(x); 132 | } 133 | Node *Access(Node *u) 134 | { 135 | Node *v = nil; 136 | while (u != nil) 137 | { 138 | Splay(u); 139 | v->p = u; 140 | u->c[1] = v; 141 | Pushup(u); 142 | u = (v = u)->p; 143 | if (u == nil) 144 | return v; 145 | } 146 | } 147 | Node *LCA(Node *u, Node *v) 148 | { 149 | Access(u); 150 | return Access(v); 151 | } 152 | Node *Link(Node *u, Node *v) 153 | { 154 | Access(u); 155 | Splay(u); 156 | u->rev = true; 157 | u->p = v; 158 | } 159 | void ChangeRoot(Node *u) 160 | { 161 | Access(u)->rev ^= 1; 162 | } 163 | Node *GetRoute(Node *u, Node *v) 164 | { 165 | ChangeRoot(u); 166 | return Access(v); 167 | } 168 | }; 169 | 170 | int n, m; 171 | SplayTree sp; 172 | 173 | int main(int argc, char const *argv[]) 174 | { 175 | while (scanf("%d", &n) != EOF) 176 | { 177 | Init(); 178 | for (int i = 0; i < n; i++) 179 | { 180 | int v; 181 | scanf("%d", &v); 182 | pos[i] = newNode(v, nil); 183 | } 184 | for (int i = 0; i < n - 1; i++) 185 | { 186 | int u, v; 187 | scanf("%d%d", &u, &v); 188 | u--, v--; 189 | sp.Link(pos[u], pos[v]); 190 | } 191 | 192 | // scanf("%d", &m); 193 | // for (int i = 0; i < m; i++) 194 | // { 195 | // int typ, u, v, c; 196 | // scanf("%d%d%d", &typ, &u, &v); 197 | // u--, v--; 198 | // if (typ == 1) 199 | // printf("%d\n", sp.GetRoute(pos[u], pos[v])->maxsum); 200 | // else 201 | // { 202 | // scanf("%d", &c); 203 | // Node *p = sp.GetRoute(pos[u], pos[v]); 204 | // p->same = true; 205 | // p->sa = c; 206 | // } 207 | // } 208 | } 209 | return 0; 210 | } 211 | \end{lstlisting} 212 | 213 | \subsubsection{维护边权} 214 | 刘汝佳的Happy Painting!\\ 215 | 查询链上边的不同颜色数量\\ 216 | 不能换根,但是可以Link和Cut\\ 217 | \begin{lstlisting}[language=c++] 218 | const int MaxN = 60000; 219 | 220 | struct Node 221 | { 222 | int size,key; 223 | 224 | int msk,lazy; 225 | 226 | Node *c[2]; 227 | Node *p; 228 | } mem[MaxN], *cur, *nil, *pos[MaxN]; 229 | 230 | Node *newNode(int v,Node *p) 231 | { 232 | cur->c[0] = cur->c[1] = nil, cur->p = p; 233 | cur->size = 1; 234 | cur->key = v; 235 | 236 | cur->msk = 0; 237 | cur->lazy = -1; 238 | 239 | return cur++; 240 | } 241 | 242 | void Init() 243 | { 244 | cur = mem; 245 | nil = newNode(0, cur); 246 | nil->size = 0; 247 | } 248 | 249 | struct SplayTree 250 | { 251 | void Pushup(Node *x) 252 | { 253 | if (x == nil) return; 254 | Pushdown(x); 255 | Pushdown(x->c[0]); 256 | Pushdown(x->c[1]); 257 | x->size = x->c[0]->size + x->c[1]->size + 1; 258 | 259 | x->msk = x->c[0]->msk | x->c[1]->msk | (1<key); 260 | } 261 | void Pushdown(Node *x) 262 | { 263 | if (x == nil) return; 264 | 265 | if (x->lazy != -1) 266 | { 267 | x->key = x->lazy; 268 | x->msk = (1<key); 269 | x->c[0]->lazy = x->c[1]->lazy = x->lazy; 270 | x->lazy = -1; 271 | } 272 | } 273 | bool isRoot(Node *x) 274 | { 275 | return (x == nil) || (x->p->c[0] != x && x->p->c[1] != x); 276 | } 277 | void Rotate(Node *x, int f) 278 | { 279 | if (isRoot(x)) return; 280 | Node *y = x->p; 281 | y->c[f ^ 1] = x->c[f], x->p = y->p; 282 | if (x->c[f] != nil) 283 | x->c[f]->p = y; 284 | if (y != nil) 285 | { 286 | if (y == y->p->c[1]) 287 | y->p->c[1] = x; 288 | else if (y == y->p->c[0]) 289 | y->p->c[0] = x; 290 | } 291 | x->c[f] = y, y->p = x; 292 | Pushup(y); 293 | } 294 | void Splay(Node *x) 295 | { 296 | static Node *stack[MaxN]; 297 | int top = 0; 298 | stack[top++] = x; 299 | for (Node *y = x; !isRoot(y); y = y->p) 300 | stack[top++] = y->p; 301 | while (top) 302 | Pushdown(stack[--top]); 303 | 304 | while (!isRoot(x)) 305 | { 306 | Node *y = x->p; 307 | if (isRoot(y)) 308 | Rotate(x, x == y->c[0]); 309 | else 310 | { 311 | int fd = y->p->c[0] == y; 312 | if (y->c[fd] == x) 313 | Rotate(x, fd ^ 1), Rotate(x, fd); 314 | else 315 | Rotate(y, fd), Rotate(x, fd); 316 | } 317 | } 318 | Pushup(x); 319 | } 320 | Node *Access(Node *u) 321 | { 322 | Node *v = nil; 323 | while (u != nil) 324 | { 325 | Splay(u); 326 | v->p = u; 327 | u->c[1] = v; 328 | Pushup(u); 329 | u = (v = u)->p; 330 | if (u == nil) return v; 331 | } 332 | } 333 | Node *Root(Node *u) 334 | { 335 | Access(u); 336 | Splay(u); 337 | for (Pushdown(u); u->c[0] != nil; u = u->c[0]) 338 | Pushdown(u); 339 | Splay(u); 340 | return u; 341 | } 342 | Node *LCA(Node *u, Node *v) 343 | { 344 | if (Root(u) != Root(v)) 345 | return nil; 346 | Access(u); 347 | return Access(v); 348 | } 349 | void Cut(Node *u) 350 | { 351 | Access(u); 352 | Splay(u); 353 | u->c[0] = u->c[0]->p = nil; 354 | Pushup(u); 355 | } 356 | void Link(Node *u, Node *v, int val) 357 | { 358 | Access(u); 359 | Splay(u); 360 | u->p = v; 361 | u->key = val; 362 | Pushup(u); 363 | } 364 | }; 365 | 366 | int cntbit(int x) 367 | { 368 | x = (x & 0x55555555) + ((x >> 1) & 0x55555555); 369 | x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 370 | x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); 371 | x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); 372 | x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF); 373 | return x; 374 | } 375 | 376 | SplayTree sp; 377 | int n,Q,f[MaxN]; 378 | 379 | int main(int argc, char const *argv[]) 380 | { 381 | while (scanf("%d%d",&n,&Q) != EOF) 382 | { 383 | Init(); 384 | for (int i = 0; i < n; i++) 385 | { 386 | scanf("%d",&f[i]); 387 | pos[i] = newNode(0, nil); 388 | } 389 | for (int i = 0; i < n; i++) 390 | { 391 | int col; 392 | scanf("%d",&col); 393 | if (f[i] > 0) 394 | sp.Link(pos[i],pos[f[i]-1],col-1); 395 | } 396 | for (int q = 0; q < Q; q++) 397 | { 398 | int typ,x,y,c; 399 | scanf("%d%d%d",&typ,&x,&y); 400 | x--,y--; 401 | if (typ == 3) 402 | { 403 | Node *lca = sp.LCA(pos[x],pos[y]); 404 | if (lca == nil || x == y) 405 | { 406 | printf("0 0\n"); 407 | continue; 408 | } 409 | int totedge = lca->c[1]->size; 410 | int msk = lca->c[1]->msk; 411 | 412 | if (pos[x] != lca) 413 | { 414 | sp.Splay(pos[x]); 415 | totedge += pos[x]->size; 416 | msk |= pos[x]->msk; 417 | } 418 | 419 | printf("%d %d\n",totedge,cntbit(msk)); 420 | } 421 | else 422 | { 423 | scanf("%d",&c); 424 | c--; 425 | if (typ == 1) 426 | { 427 | if (x == y) continue; 428 | 429 | Node *lca = sp.LCA(pos[x],pos[y]); 430 | if (pos[x] == lca) continue; 431 | 432 | sp.Cut(pos[x]); 433 | sp.Link(pos[x],pos[y],c); 434 | 435 | } 436 | else 437 | { 438 | Node *lca = sp.LCA(pos[x],pos[y]); 439 | 440 | if (lca == nil || x == y) 441 | continue; 442 | 443 | lca->c[1]->lazy = c; 444 | sp.Pushup(lca->c[1]); 445 | sp.Pushup(lca); 446 | if (pos[x] != lca) 447 | { 448 | sp.Splay(pos[x]); 449 | pos[x]->lazy = c; 450 | sp.Pushup(pos[x]); 451 | } 452 | } 453 | } 454 | } 455 | } 456 | return 0; 457 | } 458 | \end{lstlisting} -------------------------------------------------------------------------------- /datastructure/kthtree.tex: -------------------------------------------------------------------------------- 1 | \subsection{划分树} 2 | \begin{lstlisting}[language=c++] 3 | int n,m; 4 | struct elem 5 | { 6 | int v,index; 7 | }a[120000]; 8 | int d[30][120000]; 9 | int s[30][120000]; 10 | 11 | bool cmp(elem a,elem b) 12 | { 13 | if (a.v == b.v) 14 | return a.index <= b.index; 15 | return a.v < b.v; 16 | } 17 | 18 | void build(int depth,int l,int r) 19 | { 20 | if (l == r) 21 | return; 22 | int mid = (l+r)/2; 23 | int tl,tr; 24 | tl = tr = 0; 25 | for (int i = l;i <= r;i++) 26 | { 27 | if (cmp(a[d[depth][i]],a[mid])) 28 | { 29 | d[depth+1][l+tl] = d[depth][i]; 30 | tl++; 31 | } 32 | else 33 | { 34 | d[depth+1][mid+1+tr] = d[depth][i]; 35 | tr++; 36 | } 37 | s[depth][i] = tl; 38 | } 39 | build(depth+1,l,mid); 40 | build(depth+1,mid+1,r); 41 | } 42 | 43 | int find(int depth,int dl,int dr,int fl,int fr,int k) 44 | { 45 | if (fl == fr) 46 | return a[d[depth][fl]].v; 47 | int ls,rs; 48 | int mid = (dl+dr)/2; 49 | ls = (fl == dl)? 0 : s[depth][fl-1]; 50 | rs = s[depth][fr]; 51 | return (rs-ls < k)? 52 | find(depth+1,mid+1,dr,mid+fl-dl-ls+1,mid+fr-dl-rs+1,k-(rs-ls)) 53 | : find(depth+1,dl,mid,dl+ls,dl+rs-1,k); 54 | } 55 | 56 | int main() 57 | { 58 | while (scanf("%d%d",&n,&m) != EOF) 59 | { 60 | for (int i = 1;i <= n;i++) 61 | { 62 | scanf("%d",&a[i].v); 63 | a[i].index = i; 64 | } 65 | sort(a+1,a+n+1,cmp); 66 | for (int i = 1;i <= n;i++) 67 | d[0][a[i].index] = i; 68 | build(0,1,n); 69 | int l,r,k; 70 | for (int i = 1;i <= m;i++) 71 | { 72 | scanf("%d%d%d",&l,&r,&k); 73 | printf("%d\n",find(0,1,n,l,r,k)); 74 | } 75 | } 76 | return 0; 77 | } 78 | \end{lstlisting} -------------------------------------------------------------------------------- /datastructure/treap.tex: -------------------------------------------------------------------------------- 1 | \subsection{treap正式版} 2 | 支持翻转。 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int MAXN = 100000; 10 | const int MAXM = 100000; 11 | const int inf = 0x7fffffff; 12 | int a[MAXN]; 13 | struct Treap 14 | { 15 | int N; 16 | Treap() 17 | { 18 | N = 0; 19 | root = NULL; 20 | } 21 | void init() 22 | { 23 | N = 0; 24 | root = NULL; 25 | } 26 | struct Treap_Node 27 | { 28 | Treap_Node *son[2];//left & right 29 | int value, fix; 30 | bool lazy; 31 | int size; 32 | Treap_Node() {} 33 | Treap_Node(int _value) 34 | { 35 | son[0] = son[1] = NULL; 36 | value = _value; 37 | fix = rand() * rand(); 38 | lazy = 0; 39 | size = 1; 40 | } 41 | int sonSize(bool flag) 42 | { 43 | if (son[flag] == NULL) 44 | return 0; 45 | else 46 | return son[flag]->size; 47 | } 48 | } node[MAXN], *root, *pos[MAXN]; 49 | void up(Treap_Node *p) 50 | { 51 | p->size = p->sonSize(0) + p->sonSize(1) + 1; 52 | } 53 | void down(Treap_Node *p) 54 | { 55 | if (!p->lazy) 56 | return ; 57 | for (int i = 0; i < 2; i++) 58 | if (p->son[i]) 59 | p->son[i]->lazy = !p->son[i]->lazy; 60 | swap(p->son[0], p->son[1]); 61 | p->lazy = 0; 62 | } 63 | Treap_Node *merge(Treap_Node *p, Treap_Node *q) 64 | { 65 | if (p == NULL) 66 | return q; 67 | else if (q == NULL) 68 | return p; 69 | if (p->fix <= q->fix) 70 | { 71 | down(p); 72 | p->son[1] = merge(p->son[1], q); 73 | up(p); 74 | return p; 75 | } 76 | else 77 | { 78 | down(q); 79 | q->son[0] = merge(p, q->son[0]); 80 | up(q); 81 | return q; 82 | } 83 | } 84 | pair split(Treap_Node *p, int n) 85 | { 86 | if (p == NULL) 87 | return make_pair((Treap_Node *)NULL, (Treap_Node *)NULL); 88 | if (!n) 89 | return make_pair((Treap_Node *)NULL, p); 90 | if (n == p->size) 91 | return make_pair(p, (Treap_Node *)NULL); 92 | down(p); 93 | if (p->sonSize(0) >= n) 94 | { 95 | pair ret = split(p->son[0], n); 96 | p->son[0] = ret.second; 97 | up(p); 98 | return make_pair(ret.first, p); 99 | } 100 | else 101 | { 102 | pair 103 | ret = split(p->son[1], n - p->sonSize(0) - 1); 104 | p->son[1] = ret.first; 105 | up(p); 106 | return make_pair(p, ret.second); 107 | } 108 | } 109 | int smalls(Treap_Node *p,int value) 110 | { 111 | if (p==NULL) 112 | return 0; 113 | if (p->value<=value) 114 | return 1+p->sonSize(0)+smalls(p->son[1],value); 115 | else 116 | return smalls(p->son[0],value); 117 | } 118 | void insert(int value) 119 | { 120 | Treap_Node *p = &node[N++]; 121 | *p = Treap_Node(value); 122 | pair 123 | ret = split(root, smalls(root, value)); 124 | root = merge(merge(ret.first, p), ret.second); 125 | } 126 | void remove(int value) 127 | { 128 | pair ret = split(root, smalls(root, value) - 1); 129 | root = merge(ret.first, split(ret.second, 1).second); 130 | } 131 | Treap_Node *build(int s, int t) 132 | { 133 | int idx = t + s >> 1; 134 | Treap_Node *p = &node[N++]; 135 | *p = Treap_Node(a[idx]); 136 | pos[a[idx]] = p; 137 | if (idx > s) 138 | p = merge(build(s, idx - 1), p); 139 | if (idx < t) 140 | p = merge(p, build(idx + 1, t)); 141 | up(p); 142 | return p; 143 | } 144 | void build(int n) 145 | { 146 | root = build(0, n - 1); 147 | } 148 | void *reverse(int s, int t) 149 | { 150 | pair tmp1, tmp2; 151 | tmp1 = split(root, s - 1); 152 | tmp2 = split(tmp1.second, t - s + 1); 153 | tmp2.first->lazy = !tmp2.first->lazy; 154 | root = merge(tmp1.first, merge(tmp2.first, tmp2.second)); 155 | } 156 | }; 157 | Treap treap; 158 | int main() 159 | { 160 | treap.init(); 161 | int n; 162 | scanf("%d", &n); 163 | for (int i = 0; i < n; i++) 164 | scanf("%d", &a[i]); 165 | treap.build(n); 166 | } 167 | \end{lstlisting} -------------------------------------------------------------------------------- /datastructure/treearray.tex: -------------------------------------------------------------------------------- 1 | \subsection{树状数组} 2 | \begin{lstlisting}[language=c++] 3 | int read(int k) 4 | { 5 | int sum = 0; 6 | for (; k; k^=k&-k) 7 | sum+=tree[k]; 8 | return sum; 9 | } 10 | void update(int k, int v) 11 | { 12 | for (; k<=MaxN; k+=k&-k) 13 | tree[k]+=v; 14 | } 15 | int find_Kth(int k) 16 | { 17 | int idx = 0; 18 | for(int i=20; i>=0; i--) 19 | { 20 | idx |= 1 << i; 21 | if(idx <= MaxN && tree[idx] < k) 22 | k -= tree[idx]; 23 | else idx ^= 1 << i; 24 | } 25 | return idx + 1; 26 | } 27 | \end{lstlisting} 28 | -------------------------------------------------------------------------------- /dp.tex: -------------------------------------------------------------------------------- 1 | \section{动态规划} 2 | \input dp/slope.tex 3 | \input dp/rmq.tex 4 | \input dp/lis2.tex 5 | \input dp/scdp.tex -------------------------------------------------------------------------------- /dp/lis2.tex: -------------------------------------------------------------------------------- 1 | \subsection{二维LIS} 2 | \begin{lstlisting}[language=c++] 3 | #include 4 | #include 5 | using namespace std; 6 | map mp[100001]; 7 | bool check(int idx,int x,int y) 8 | { 9 | if (!idx) return 1; 10 | if (mp[idx].begin()->first>=x) return 0; 11 | map ::iterator it=mp[idx].lower_bound(x); 12 | it--; 13 | if (it->second ::iterator itl=mp[idx].lower_bound(x),itr=itl; 37 | while (itr!=mp[idx].end() && itr->second>y) itr++; 38 | if (mp[idx].find(x)!=mp[idx].end()) 39 | y=min(y,mp[idx][x]); 40 | if (itl!=itr) mp[idx].erase(itl,itr); 41 | if (mp[idx].find(x)==mp[idx].end() || mp[idx][x]>y) 42 | mp[idx][x]=y; 43 | } 44 | printf("%d\n",r); 45 | return 0; 46 | } 47 | \end{lstlisting} 48 | -------------------------------------------------------------------------------- /dp/rmq.tex: -------------------------------------------------------------------------------- 1 | \subsection{RMQ二版} 2 | \begin{lstlisting}[language=c++] 3 | void init() 4 | { 5 | int i,j; 6 | int n=N,k=1,l=0; 7 | for (i=0; ik*2) 11 | { 12 | k*=2; 13 | l++; 14 | } 15 | lent[i+1]=l; 16 | } 17 | for (j=1; (1< 0) 34 | { 35 | key = setbit(key,i,tmp-1); 36 | cov = setbit(cov,i,1); 37 | } 38 | } 39 | } 40 | 41 | int encode(int key,int cov) 42 | { 43 | int res = 0,tmp; 44 | for (int i = 0; i < m+1; i++) 45 | { 46 | tmp = getbit(cov,i); 47 | if (tmp > 0) 48 | { 49 | tmp = getbit(key,i); 50 | res = setbit(res,i,tmp+1); 51 | } 52 | } 53 | return res; 54 | } 55 | 56 | void update(int a,int key,int cov,int val) 57 | { 58 | int msk = encode(key,cov); 59 | int pos; 60 | if (dp[a][msk] < val) 61 | { 62 | dp[a][msk] = val; 63 | pos = dp[a].fint(msk); 64 | pre[now][pos] = pr; 65 | preuse[now][pos] = pru; 66 | } 67 | } 68 | 69 | int count3(int sta) 70 | { 71 | int res = 0; 72 | for (int i = 0; i < m+1; i++) 73 | if (getbit(sta,i) == 3) 74 | res++; 75 | return res; 76 | } 77 | 78 | void expand(int sta) 79 | { 80 | top = 0; 81 | for (int i = 0; i < m+1; i++) 82 | if (getbit(sta,i) == 1) 83 | s[top++] = i; 84 | else if (getbit(sta,i) == 2) 85 | { 86 | w[s[top-1]] = i; 87 | w[i] = s[top-1]; 88 | top--; 89 | } 90 | } 91 | 92 | int main() 93 | { 94 | //freopen("TD.in","r",stdin); 95 | //freopen("TDM.out","w",stdout); 96 | bit[0] = 1; 97 | for (int i = 1; i < 12; i++) bit[i] = bit[i-1]*5; 98 | int t; 99 | scanf("%d",&t); 100 | dp[0].init(); 101 | dp[1].init(); 102 | for (int ft = 1; ft <= t; ft++) 103 | { 104 | scanf("%d%d",&n,&m); 105 | res = 0; 106 | memset(mp,0,sizeof(mp)); 107 | memset(pre,0,sizeof(pre)); 108 | memset(preuse,0,sizeof(preuse)); 109 | for (int i = 0; i < n; i++) 110 | { 111 | scanf("%s",buf[i]); 112 | for (int j = 0; j < m; j++) 113 | if (buf[i][j] == '.') 114 | mp[i][j] = 1; 115 | else if (buf[i][j] != 'B') 116 | mp[i][j] = 2; 117 | } 118 | dp[0].clear(); 119 | dp[1].clear(); 120 | flag = 0; 121 | dp[flag][0] = 0; 122 | int res = 0; 123 | now = 0; 124 | for (int i = 0; i < n; i++) 125 | { 126 | for (int j = 0; j < m; j++) 127 | { 128 | dp[!flag].clear(); 129 | for (int k = 0; k < dp[flag].N; k++) 130 | { 131 | msk = dp[flag].ele[k].key; 132 | pr = k; 133 | val = dp[flag].ele[k].val; 134 | decode(msk,key,cov); 135 | l = getbit(key,j); 136 | u = getbit(key,j+1); 137 | if (mp[i][j] == 0)//是障碍 138 | { 139 | if (l == 0 && u == 0) 140 | { 141 | pru = 0; 142 | update(!flag,key,setbit(setbit(cov,j,0),j+1,0),val); 143 | } 144 | } 145 | else 146 | { 147 | if (mp[i][j] == 1 && l == 0 && u == 0)//不要插头 148 | { 149 | pru = 1; 150 | update(!flag,key,setbit(setbit(cov,j,0),j+1,0),val); 151 | } 152 | if (getbit(cov,j) == 1 && l == 0) continue;//不可以在这里搞插头 153 | if (getbit(cov,j+1) == 1 && u == 0) continue; 154 | cov = setbit(setbit(cov,j,1),j+1,1);//更新覆盖情况 155 | upd = setbit(setbit(key,j,0),j+1,0); 156 | pru = 2; 157 | if (mp[i][j] == 2) 158 | { 159 | if (l == 0 && u == 0) 160 | { 161 | if (count3(key) < 2)//可以新建独立插头 162 | { 163 | if (mp[i][j+1] != 0) 164 | update(!flag,setbit(setbit(key,j,0),j+1,3),cov,val+1); 165 | if (mp[i+1][j] != 0) 166 | update(!flag,setbit(setbit(key,j,3),j+1,0),cov,val+1); 167 | } 168 | } 169 | else if (l == 0 || u == 0) 170 | { 171 | if (l+u < 3 && count3(key) < 2)//可以用一个独立插头来结束这条路径 172 | { 173 | expand(key); 174 | if (l > 0) 175 | update(!flag,setbit(upd,w[j],3),cov,val+1); 176 | else 177 | update(!flag,setbit(upd,w[j+1],3),cov,val+1); 178 | } 179 | else if (l+u == 3 && upd == 0)//路径的一端 180 | { 181 | if (res < val+1) 182 | { 183 | res = val+1; 184 | resnow = now-1; 185 | resmsk = k; 186 | } 187 | } 188 | } 189 | } 190 | else if (l == 0 && u == 0) 191 | { 192 | if (mp[i][j+1] != 0 && mp[i+1][j] != 0)//可以新建插头 193 | update(!flag,setbit(setbit(key,j,1),j+1,2),cov,val+1); 194 | } 195 | else if (l == 0 || u == 0) 196 | { 197 | if (mp[i][j+1] != 0)//可以延续插头 198 | update(!flag,setbit(upd,j+1,l+u),cov,val+1); 199 | if (mp[i+1][j] != 0)//可以延续插头 200 | update(!flag,setbit(upd,j,l+u),cov,val+1); 201 | } 202 | else if (l == u) 203 | { 204 | if (l < 3) //合并两个相同的括号 205 | { 206 | expand(key); 207 | if (l == 1) 208 | update(!flag,setbit(upd,w[j+1],1),cov,val+1); 209 | else 210 | update(!flag,setbit(upd,w[j],2),cov,val+1); 211 | } 212 | else if (upd == 0)//合并两个独立插头 213 | { 214 | if (res < val+1) 215 | { 216 | res = val+1; 217 | resnow = now-1; 218 | resmsk = k; 219 | } 220 | } 221 | } 222 | else if (l == 3 || u == 3)//合并独立插头与括号 223 | { 224 | expand(key); 225 | if (l == 3) 226 | update(!flag,setbit(upd,w[j+1],3),cov,val+1); 227 | else 228 | update(!flag,setbit(upd,w[j],3),cov,val+1); 229 | } 230 | else if (l == 2 || u == 1) //合并)( 231 | update(!flag,upd,cov,val+1); 232 | } 233 | } 234 | flag = !flag; 235 | now++; 236 | } 237 | if (i+1 == n) break; 238 | 239 | dp[!flag].clear(); 240 | for (int k = 0; k < dp[flag].N; k++) 241 | { 242 | msk = dp[flag].ele[k].key; 243 | pr = k; 244 | val = dp[flag].ele[k].val; 245 | pru = 0; 246 | decode(msk,key,cov); 247 | update(!flag,key*bit[1],cov*bit[1],val); 248 | } 249 | now++; 250 | flag = !flag; 251 | } 252 | 253 | printf("Case %d: %d\n",ft,res); 254 | for (int i = resnow; i >= 0; i--) 255 | { 256 | if (preuse[i][resmsk] == 1) 257 | buf[i/(m+1)][i%(m+1)] = 'W'; 258 | resmsk = pre[i][resmsk]; 259 | } 260 | for (int i = 0; i < n; i++) 261 | printf("%s\n",buf[i]); 262 | printf("\n"); 263 | } 264 | return 0; 265 | } 266 | \end{lstlisting} -------------------------------------------------------------------------------- /dp/slope.tex: -------------------------------------------------------------------------------- 1 | \subsection{斜率优化} 2 | \begin{lstlisting}[language=c++] 3 | #include 4 | #include 5 | using namespace std; 6 | int a[1000],sum[1001],dp[1000][1000]; 7 | int deque[1000]; 8 | const int inf=0x7fffffff; 9 | int N,s,t; 10 | int calc(int i,int l,int j)//决策值计算 11 | { 12 | return dp[j][l-1]-(sum[i]-sum[j])*(sum[N]-sum[i]); 13 | } 14 | bool check(int i,int l)//尾端判断 15 | { 16 | int k1=deque[t-1],k2=deque[t-2]; 17 | return (long long)(dp[k1][l]-dp[k2][l])*(sum[i]-sum[k1])>(long long)(dp[i][l]-dp[k1][l])*(sum[k1]-sum[k2]); 18 | } 19 | int main() 20 | { 21 | int n,m; 22 | while (scanf("%d%d",&n,&m),n) 23 | { 24 | for (int i=0; i1 && check(i-1,l-1)) t--; 48 | deque[t++]=i-1;//决策加入 49 | while (t-s>1 && calc(i,l,deque[s])>calc(i,l,deque[s+1])) s++; 50 | dp[i][l]=calc(i,l,deque[s]); 51 | } 52 | } 53 | int ans=0x7fffffff; 54 | for (int i=m; i eps) 61 | dfs(p, f); 62 | else 63 | { 64 | add.a = b, add.b = a, add.c = p, add.ok = 1; 65 | to[p][b] = to[a][p] = to[b][a] = cnt; 66 | F[cnt++] = add; 67 | } 68 | } 69 | } 70 | void dfs(int p, int cur) 71 | { 72 | F[cur].ok = 0; 73 | deal(p, F[cur].b, F[cur].a); 74 | deal(p, F[cur].c, F[cur].b); 75 | deal(p, F[cur].a, F[cur].c); 76 | } 77 | bool same(int s, int t) 78 | { 79 | pt &a = P[F[s].a], &b = P[F[s].b], &c = P[F[s].c]; 80 | return fabs(volume(a, b, c, P[F[t].a])) < eps && fabs(volume(a, b, c, 81 | P[F[t].b])) < eps && fabs(volume(a, b, c, P[F[t].c])) < eps; 82 | } 83 | void construct() 84 | { 85 | cnt = 0; 86 | if (n < 4) 87 | return; 88 | bool sb = 1; 89 | for (int i = 1; i < n; i++) 90 | { 91 | if (vlen(P[0] - P[i]) > eps) 92 | { 93 | swap(P[1], P[i]); 94 | sb = 0; 95 | break; 96 | } 97 | } 98 | if (sb)return; 99 | sb = 1; 100 | for (int i = 2; i < n; i++) 101 | { 102 | if (vlen((P[0] - P[1]) * (P[1] - P[i])) > eps) 103 | { 104 | swap(P[2], P[i]); 105 | sb = 0; 106 | break; 107 | } 108 | } 109 | if (sb)return; 110 | sb = 1; 111 | for (int i = 3; i < n; i++) 112 | { 113 | if (fabs((P[0] - P[1]) * (P[1] - P[2]) ^ (P[0] - P[i])) > eps) 114 | { 115 | swap(P[3], P[i]); 116 | sb = 0; 117 | break; 118 | } 119 | } 120 | if (sb)return; 121 | fac add; 122 | for (int i = 0; i < 4; i++) 123 | { 124 | add.a = (i+1)%4, add.b = (i+2)%4, add.c = (i+3)%4, add.ok = 1; 125 | if (ptof(P[i], add) > 0) 126 | swap(add.b, add.c); 127 | to[add.a][add.b] = to[add.b][add.c] = to[add.c][add.a] = cnt; 128 | F[cnt++] = add; 129 | } 130 | for (int i = 4; i < n; i++) 131 | { 132 | for (int j = 0; j < cnt; j++) 133 | { 134 | if (F[j].ok && ptof(P[i], F[j]) > eps) 135 | { 136 | dfs(i, j); 137 | break; 138 | } 139 | } 140 | } 141 | int tmp = cnt; 142 | cnt = 0; 143 | for (int i = 0; i < tmp; i++) 144 | { 145 | if (F[i].ok) 146 | { 147 | F[cnt++] = F[i]; 148 | } 149 | } 150 | } 151 | //表面积 152 | double area() 153 | { 154 | double ret = 0.0; 155 | for (int i = 0; i < cnt; i++) 156 | { 157 | ret += area(P[F[i].a], P[F[i].b], P[F[i].c]); 158 | } 159 | return ret / 2.0; 160 | } 161 | //体积 162 | double volume() 163 | { 164 | pt O(0, 0, 0); 165 | double ret = 0.0; 166 | for (int i = 0; i < cnt; i++) 167 | { 168 | ret += volume(O, P[F[i].a], P[F[i].b], P[F[i].c]); 169 | } 170 | return fabs(ret / 6.0); 171 | } 172 | //表面三角形数 173 | int facetCnt_tri() 174 | { 175 | return cnt; 176 | } 177 | //表面多边形数 178 | int facetCnt() 179 | { 180 | int ans = 0; 181 | for (int i = 0; i < cnt; i++) 182 | { 183 | bool nb = 1; 184 | for (int j = 0; j < i; j++) 185 | { 186 | if (same(i, j)) 187 | { 188 | nb = 0; 189 | break; 190 | } 191 | } 192 | ans += nb; 193 | } 194 | return ans; 195 | } 196 | 197 | pt Fc[MAXV*8]; 198 | double V[MAXV*8]; 199 | pt Center()//重心 200 | { 201 | pt O(0,0,0); 202 | for (int i = 0; i < cnt; i++) 203 | { 204 | Fc[i].x = (O.x+P[F[i].a].x+P[F[i].b].x+P[F[i].c].x)/4.0; 205 | Fc[i].y = (O.y+P[F[i].a].y+P[F[i].b].y+P[F[i].c].y)/4.0; 206 | Fc[i].z = (O.z+P[F[i].a].z+P[F[i].b].z+P[F[i].c].z)/4.0; 207 | V[i] = volume(O,P[F[i].a],P[F[i].b],P[F[i].c]); 208 | } 209 | pt res = Fc[0],tmp; 210 | double m = V[0]; 211 | for (int i = 1; i < cnt; i++) 212 | { 213 | if (fabs(m+V[i]) < eps) 214 | V[i] += eps; 215 | tmp.x = (m*res.x+V[i]*Fc[i].x)/(m+V[i]); 216 | tmp.y = (m*res.y+V[i]*Fc[i].y)/(m+V[i]); 217 | tmp.z = (m*res.z+V[i]*Fc[i].z)/(m+V[i]); 218 | m += V[i]; 219 | res = tmp; 220 | } 221 | return res; 222 | } 223 | }; 224 | 225 | _3DCH hull; 226 | 227 | int main() 228 | { 229 | while (scanf("%d",&hull.n) != EOF) 230 | { 231 | for (int i = 0; i < hull.n; i++) 232 | scanf("%lf%lf%lf",&hull.P[i].x,&hull.P[i].y,&hull.P[i].z); 233 | hull.construct(); 234 | } 235 | return 0; 236 | } 237 | \end{lstlisting} 238 | 239 | -------------------------------------------------------------------------------- /geometric/GS.tex: -------------------------------------------------------------------------------- 1 | \subsection{凸包} 2 | 得到的凸包按照逆时针方向排序。 3 | \begin{lstlisting}[language=c++] 4 | //判断是否是共点或者共线用 5 | bool conPoint(Point p[],int n) 6 | { 7 | for (int i = 1;i < n;i++) 8 | if (p[i].x != p[0].x || p[i].y != p[0].y) 9 | return false; 10 | return true; 11 | } 12 | bool conLine(Point p[],int n) 13 | { 14 | for (int i = 2;i < n;i++) 15 | if ((p[i]-p[0])*(p[1]-p[0]) != 0) 16 | return false; 17 | return true; 18 | } 19 | 20 | bool GScmp(Point a, Point b) 21 | { 22 | if (fabs(a.x - b.x) < eps) 23 | return a.y < b.y - eps; 24 | return a.x < b.x - eps; 25 | } 26 | 27 | void GS(Point p[],int n,Point res[],int &resn) 28 | { 29 | resn = 0; 30 | int top = 0; 31 | sort(p,p+n,GScmp); 32 | 33 | if (conPoint(p,n)) 34 | { 35 | res[resn++] = p[0]; 36 | return; 37 | } 38 | if (conLine(p,n)) 39 | { 40 | res[resn++] = p[0]; 41 | res[resn++] = p[n-1]; 42 | return; 43 | } 44 | 45 | for (int i = 0;i < n;) 46 | if (resn < 2 || 47 | (res[resn-1]-res[resn-2])*(p[i]-res[resn-1]) > 0) 48 | res[resn++] = p[i++]; 49 | else 50 | --resn; 51 | top = resn-1; 52 | for (int i = n-2;i >= 0;) 53 | if (resn < top+2 || 54 | res[resn-1]-res[resn-2])*(p[i]-res[resn-1]) > 0) 55 | res[resn++] = p[i--]; 56 | else 57 | --resn; 58 | resn--; 59 | } 60 | \end{lstlisting} 61 | -------------------------------------------------------------------------------- /geometric/HPI.tex: -------------------------------------------------------------------------------- 1 | \subsection{半平面交} 2 | 直线左边代表有效区域。 3 | \begin{lstlisting}[language=c++] 4 | bool HPIcmp(Line a, Line b) 5 | { 6 | if (fabs(a.k - b.k) > eps) return a.k < b.k; 7 | return ((a.s - b.s) * (b.e-b.s)) < 0; 8 | } 9 | 10 | Line Q[100]; 11 | void HPI(Line line[], int n, Point res[], int &resn) 12 | { 13 | int tot = n; 14 | sort(line, line + n, HPIcmp); 15 | tot = 1; 16 | for (int i = 1; i < n; i++) 17 | if (fabs(line[i].k - line[i - 1].k) > eps) 18 | line[tot++] = line[i]; 19 | int head = 0, tail = 1; 20 | Q[0] = line[0]; 21 | Q[1] = line[1]; 22 | resn = 0; 23 | for (int i = 2; i < tot; i++) 24 | { 25 | if (fabs((Q[tail].e-Q[tail].s)*(Q[tail - 1].e-Q[tail - 1].s)) < eps || 26 | fabs((Q[head].e-Q[head].s)*(Q[head + 1].e-Q[head + 1].s)) < eps) 27 | return; 28 | while (head < tail && (((Q[tail]&Q[tail - 1]) - line[i].s) * (line[i].e-line[i].s)) > eps) 29 | tail--; 30 | while (head < tail && (((Q[head]&Q[head + 1]) - line[i].s) * (line[i].e-line[i].s)) > eps) 31 | head++; 32 | Q[++tail] = line[i]; 33 | } 34 | while (head < tail && (((Q[tail]&Q[tail - 1]) - Q[head].s) * (Q[head].e-Q[head].s)) > eps) 35 | tail--; 36 | while (head < tail && (((Q[head]&Q[head + 1]) - Q[tail].s) * (Q[tail].e-Q[tail].s)) > eps) 37 | head++; 38 | if (tail <= head + 1) return; 39 | for (int i = head; i < tail; i++) 40 | res[resn++] = Q[i] & Q[i + 1]; 41 | if (head < tail + 1) 42 | res[resn++] = Q[head] & Q[tail]; 43 | } 44 | \end{lstlisting} 45 | -------------------------------------------------------------------------------- /geometric/KDtree.tex: -------------------------------------------------------------------------------- 1 | \subsection{KD树} 2 | 查找某个点距离最近的点,基本思想是每次分治把点分成两部分,建议按照坐标规模决定是垂直划分还是水平划分,查找时先往分到的那一部分查找,然后根据当前最优答案决定是否去另一个区间查找。 3 | \begin{lstlisting}[language=c++] 4 | bool Div[MaxN]; 5 | void BuildKD(int deep,int l, int r, Point p[])\\`记得备份一下P` 6 | { 7 | if (l > r) return; 8 | int mid = l + r >> 1; 9 | int minX, minY, maxX, maxY; 10 | minX = min_element(p + l, p + r + 1, cmpX)->x; 11 | minY = min_element(p + l, p + r + 1, cmpY)->y; 12 | maxX = max_element(p + l, p + r + 1, cmpX)->x; 13 | maxY = max_element(p + l, p + r + 1, cmpY)->y; 14 | Div[mid] = (maxX - minX >= maxY - minY); 15 | nth_element(p + l, p + mid, p + r + 1, Div[mid] ? cmpX : cmpY); 16 | BuildKD(l, mid - 1, p); 17 | BuildKD(mid + 1, r, p); 18 | } 19 | 20 | long long res; 21 | void Find(int l, int r, Point a, Point p[])\\`查找` 22 | { 23 | if (l > r) return; 24 | int mid = l + r >> 1; 25 | long long dist = dist2(a, p[mid]); 26 | if (dist > 0)//如果有重点不能这样判断 27 | res = min(res, dist); 28 | long long d = Div[mid] ? (a.x - p[mid].x) : (a.y - p[mid].y); 29 | int l1, l2, r1, r2; 30 | l1 = l, l2 = mid + 1; 31 | r1 = mid - 1, r2 = r; 32 | if (d > 0) 33 | swap(l1, l2), swap(r1, r2); 34 | Find(l1, r1, a, p); 35 | if (d * d < res) 36 | Find(l2, r2, a, p); 37 | } 38 | \end{lstlisting} 39 | \subsubsection{例题} 40 | 查询一个点为中心的给定正方形内所有点并删除(2012金华网赛A)\\ 41 | \begin{lstlisting}[language=c++] 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | using namespace std; 49 | 50 | const int MaxN = 100000; 51 | struct Point 52 | { 53 | int x,y,r; 54 | int id; 55 | bool del; 56 | }; 57 | 58 | int cmpTyp; 59 | bool cmp(const Point& a,const Point& b) 60 | { 61 | if (cmpTyp == 0) 62 | return a.x < b.x; 63 | else 64 | return a.y < b.y; 65 | } 66 | 67 | int cnt[MaxN]; 68 | bool Div[MaxN]; 69 | int minX[MaxN],minY[MaxN],maxX[MaxN],maxY[MaxN]; 70 | void BuildKD(int l,int r,Point p[]) 71 | { 72 | if (l > r) return; 73 | int mid = l+r>>1; 74 | cmpTyp = 0; 75 | minX[mid] = min_element(p+l,p+r+1,cmp)->x; 76 | maxX[mid] = max_element(p+l,p+r+1,cmp)->x; 77 | cmpTyp = 1; 78 | minY[mid] = min_element(p+l,p+r+1,cmp)->y; 79 | maxY[mid] = max_element(p+l,p+r+1,cmp)->y; 80 | 81 | cnt[mid] = r-l+1; 82 | cmpTyp = Div[mid] = (maxX[mid]-minX[mid] < maxY[mid]-minY[mid]); 83 | nth_element(p+l,p+mid,p+r+1,cmp); 84 | BuildKD(l,mid-1,p); 85 | BuildKD(mid+1,r,p); 86 | } 87 | 88 | queue Q; 89 | int Find(int l,int r,Point a,Point p[]) 90 | { 91 | if (l > r) return 0; 92 | int mid = l+r>>1; 93 | if (cnt[mid] == 0) return 0; 94 | 95 | if (maxX[mid] < a.x-a.r || 96 | minX[mid] > a.x+a.r || 97 | maxY[mid] < a.y-a.r || 98 | minY[mid] > a.y+a.r) 99 | return 0; 100 | 101 | int totdel = 0; 102 | 103 | if (p[mid].del == false) 104 | if (abs(p[mid].x-a.x) <= a.r && abs(p[mid].y-a.y) <= a.r) 105 | { 106 | p[mid].del = true; 107 | Q.push(p[mid].id); 108 | totdel++; 109 | } 110 | 111 | totdel += Find(l,mid-1,a,p); 112 | totdel += Find(mid+1,r,a,p); 113 | 114 | cnt[mid] -= totdel; 115 | 116 | return totdel; 117 | } 118 | 119 | Point p[MaxN],tp[MaxN]; 120 | int n; 121 | 122 | int main() 123 | { 124 | int cas = 1; 125 | while (true) 126 | { 127 | scanf("%d",&n); 128 | if (n == 0) break; 129 | 130 | for (int i = 0;i < n;i++) 131 | { 132 | p[i].id = i; 133 | int tx,ty; 134 | scanf("%d%d%d",&tx,&ty,&p[i].r); 135 | p[i].x = tx-ty; 136 | p[i].y = tx+ty; 137 | p[i].del = false; 138 | tp[i] = p[i]; 139 | } 140 | BuildKD(0,n-1,tp); 141 | 142 | printf("Case #%d:\n",cas++); 143 | int q; 144 | scanf("%d",&q); 145 | for (int i = 0;i < q;i++) 146 | { 147 | int id; 148 | scanf("%d",&id); 149 | int res = 0; 150 | id--; 151 | Q.push(id); 152 | while (!Q.empty()) 153 | { 154 | int now = Q.front(); 155 | Q.pop(); 156 | if (p[now].del == true) continue; 157 | p[now].del = true; 158 | res += Find(0,n-1,p[now],tp); 159 | } 160 | printf("%d\n",res); 161 | } 162 | } 163 | return 0; 164 | } 165 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/RotatingCalipers.tex: -------------------------------------------------------------------------------- 1 | \subsection{旋转卡壳} 2 | “对踵”\\ 3 | \subsubsection{单个凸包} 4 | \begin{lstlisting}[language=c++] 5 | void solve(Point p[],int n) 6 | { 7 | Point v; 8 | int cur = 1; 9 | for (int i = 0;i < n;i++) 10 | { 11 | v = p[i]-p[(i+1)%n]; 12 | while (v*(p[(cur+1)%n]-p[cur]) < 0) 13 | cur = (cur+1)%n; 14 | //p[cur] -> p[i] 15 | //p[cur] -> p[i+1] 16 | //p[cur] -> (p[i],p[i+1]) 17 | } 18 | } 19 | \end{lstlisting} 20 | \subsubsection{两个凸包} 21 | 注意初始点的选取,代码只是个示例。\\ 22 | 有时候答案需要取solve(p0,n,p1,m)和solve(p1,m,p0,n)的最优值。\\ 23 | 何老鱼说我的是错的。。\\ 24 | \begin{lstlisting}[language=c++] 25 | void solve(Point p0[],int n,Point p1[],int m) 26 | { 27 | Point v; 28 | int cur = 0; 29 | for (int i = 0;i < n;i++) 30 | { 31 | v = p0[i]-p0[(i+1)%n]; 32 | while (v*(p1[(cur+1)%m]-p1[cur]) < 0) 33 | cur = (cur+1)%m; 34 | //p1[cur] -> p0[i] 35 | //p1[cur] -> p0[i+1] 36 | //p1[cur] -> (p0[i],p0[i+1]) 37 | } 38 | } 39 | \end{lstlisting} 40 | \subsubsection{外接矩形} 41 | \begin{lstlisting}[language=c++] 42 | void solve() 43 | { 44 | resa = resb = 1e100; 45 | double dis1,dis2; 46 | Point xp[4]; 47 | Line l[4]; 48 | int a,b,c,d; 49 | int sa,sb,sc,sd; 50 | a = b = c = d = 0; 51 | sa = sb = sc = sd = 0; 52 | Point va,vb,vc,vd; 53 | for (a = 0; a < n; a++) 54 | { 55 | va = Point(p[a],p[(a+1)%n]); 56 | vc = Point(-va.x,-va.y); 57 | vb = Point(-va.y,va.x); 58 | vd = Point(-vb.x,-vb.y); 59 | if (sb < sa) 60 | { 61 | b = a; 62 | sb = sa; 63 | } 64 | while (xmult(vb,Point(p[b],p[(b+1)%n])) < 0) 65 | { 66 | b = (b+1)%n; 67 | sb++; 68 | } 69 | if (sc < sb) 70 | { 71 | c = b; 72 | sc = sb; 73 | } 74 | while (xmult(vc,Point(p[c],p[(c+1)%n])) < 0) 75 | { 76 | c = (c+1)%n; 77 | sc++; 78 | } 79 | if (sd < sc) 80 | { 81 | d = c; 82 | sd = sc; 83 | } 84 | while (xmult(vd,Point(p[d],p[(d+1)%n])) < 0) 85 | { 86 | d = (d+1)%n; 87 | sd++; 88 | } 89 | 90 | //`卡在p[a],p[b],p[c],p[d]上` 91 | sa++; 92 | } 93 | } 94 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/areaofcircles.tex: -------------------------------------------------------------------------------- 1 | \subsection{多圆面积并} 2 | \subsubsection{去重} 3 | 有时候可能需要去掉不需要的圆 4 | \begin{lstlisting}[language=c++] 5 | for (int i = 0; i < n; i++) 6 | { 7 | scanf("%lf%lf%lf",&c[i].c.x,&c[i].c.y,&c[i].r); 8 | del[i] = false; 9 | } 10 | for (int i = 0; i < n; i++) 11 | if (del[i] == false) 12 | { 13 | if (c[i].r == 0.0) del[i] = true; 14 | for (int j = 0; j < n; j++) 15 | if (i != j) 16 | if (del[j] == false) 17 | if (cmp(Point(c[i].c,c[j].c).Len()+c[i].r,c[j].r) <= 0) 18 | del[i] = true; 19 | } 20 | tn = n; 21 | n = 0; 22 | for (int i = 0; i < tn; i++) 23 | if (del[i] == false) 24 | c[n++] = c[i]; 25 | \end{lstlisting} 26 | 27 | \subsubsection{圆并} 28 | $ans[i]$表示被覆盖$i$次的面积 29 | \begin{lstlisting}[language=c++] 30 | const double pi = acos(-1.0); 31 | const double eps = 1e-8; 32 | struct Point 33 | { 34 | double x,y; 35 | Point(){} 36 | Point(double _x,double _y) 37 | { 38 | x = _x; 39 | y = _y; 40 | } 41 | double Length() 42 | { 43 | return sqrt(x*x+y*y); 44 | } 45 | }; 46 | struct Circle 47 | { 48 | Point c; 49 | double r; 50 | }; 51 | struct Event 52 | { 53 | double tim; 54 | int typ; 55 | Event(){} 56 | Event(double _tim,int _typ) 57 | { 58 | tim = _tim; 59 | typ = _typ; 60 | } 61 | }; 62 | 63 | int cmp(const double& a,const double& b) 64 | { 65 | if (fabs(a-b) < eps) return 0; 66 | if (a < b) return -1; 67 | return 1; 68 | } 69 | 70 | bool Eventcmp(const Event& a,const Event& b) 71 | { 72 | return cmp(a.tim,b.tim) < 0; 73 | } 74 | 75 | double Area(double theta,double r) 76 | { 77 | return 0.5*r*r*(theta-sin(theta)); 78 | } 79 | 80 | double xmult(Point a,Point b) 81 | { 82 | return a.x*b.y-a.y*b.x; 83 | } 84 | 85 | int n,cur,tote; 86 | Circle c[1000]; 87 | double ans[1001],pre[1001],AB,AC,BC,theta,fai,a0,a1; 88 | Event e[4000]; 89 | Point lab; 90 | 91 | int main() 92 | { 93 | while (scanf("%d",&n) != EOF) 94 | { 95 | for (int i = 0;i < n;i++) 96 | scanf("%lf%lf%lf",&c[i].c.x,&c[i].c.y,&c[i].r); 97 | for (int i = 1;i <= n;i++) 98 | ans[i] = 0.0; 99 | for (int i = 0;i < n;i++) 100 | { 101 | tote = 0; 102 | e[tote++] = Event(-pi,1); 103 | e[tote++] = Event(pi,-1); 104 | for (int j = 0;j < n;j++) 105 | if (j != i) 106 | { 107 | lab = Point(c[j].c.x-c[i].c.x,c[j].c.y-c[i].c.y); 108 | AB = lab.Length(); 109 | AC = c[i].r; 110 | BC = c[j].r; 111 | if (cmp(AB+AC,BC) <= 0) 112 | { 113 | e[tote++] = Event(-pi,1); 114 | e[tote++] = Event(pi,-1); 115 | continue; 116 | } 117 | if (cmp(AB+BC,AC) <= 0) continue; 118 | if (cmp(AB,AC+BC) > 0) continue; 119 | theta = atan2(lab.y,lab.x); 120 | fai = acos((AC*AC+AB*AB-BC*BC)/(2.0*AC*AB)); 121 | a0 = theta-fai; 122 | if (cmp(a0,-pi) < 0) a0 += 2*pi; 123 | a1 = theta+fai; 124 | if (cmp(a1,pi) > 0) a1 -= 2*pi; 125 | if (cmp(a0,a1) > 0) 126 | { 127 | e[tote++] = Event(a0,1); 128 | e[tote++] = Event(pi,-1); 129 | e[tote++] = Event(-pi,1); 130 | e[tote++] = Event(a1,-1); 131 | } 132 | else 133 | { 134 | e[tote++] = Event(a0,1); 135 | e[tote++] = Event(a1,-1); 136 | } 137 | } 138 | sort(e,e+tote,Eventcmp); 139 | cur = 0; 140 | for (int j = 0;j < tote;j++) 141 | { 142 | if (cur != 0 && cmp(e[j].tim,pre[cur]) != 0) 143 | { 144 | ans[cur] += Area(e[j].tim-pre[cur],c[i].r); 145 | ans[cur] += xmult(Point(c[i].c.x+c[i].r*cos(pre[cur]),c[i].c.y+c[i].r*sin(pre[cur])), 146 | Point(c[i].c.x+c[i].r*cos(e[j].tim),c[i].c.y+c[i].r*sin(e[j].tim)))/2.0; 147 | } 148 | cur += e[j].typ; 149 | pre[cur] = e[j].tim; 150 | } 151 | } 152 | for (int i = 1;i < n;i++) 153 | ans[i] -= ans[i+1]; 154 | for (int i = 1;i <= n;i++) 155 | printf("[%d] = %.3f\n",i,ans[i]); 156 | } 157 | return 0; 158 | } 159 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/base.tex: -------------------------------------------------------------------------------- 1 | \subsection{基本函数} 2 | \subsubsection{Point定义} 3 | \begin{lstlisting}[language=c++] 4 | struct Point 5 | { 6 | double x, y; 7 | Point() {} 8 | Point(double _x, double _y) 9 | { 10 | x = _x, y = _y; 11 | } 12 | Point operator -(const Point &b)const 13 | { 14 | return Point(x-b.x, y-b.y); 15 | } 16 | double operator *(const Point &b)const 17 | { 18 | return x*b.y-y*b.x; 19 | } 20 | double operator &(const Point &b)const 21 | { 22 | return x*b.x+y*b.y; 23 | } 24 | void transXY(double B) 25 | { 26 | double tx = x,ty = y; 27 | x = tx*cos(B)-ty*sin(B); 28 | y = tx*sin(B)+ty*cos(B); 29 | } 30 | }; 31 | \end{lstlisting} 32 | 33 | \subsubsection{Line定义} 34 | \begin{lstlisting}[language=c++] 35 | struct Line 36 | { 37 | Point s, e; 38 | double k; 39 | Line() {} 40 | Line(Point _s, Point _e) 41 | { 42 | s = _s, e = _e; 43 | k = atan2(e.y-s.y, e.x-s.x); 44 | } 45 | Point operator &(const Line &b)const 46 | { 47 | Point res = s; 48 | //注意:有些题目可能会有直线相交或者重合情况 49 | //可以把返回值改成`pair`来返回两直线的状态。 50 | double t = ((s-b.s)*(b.s-b.e))/((s-e)*(b.s-b.e)); 51 | res.x += (e.x-s.x)*t; 52 | res.y += (e.y-s.y)*t; 53 | return res; 54 | } 55 | }; 56 | \end{lstlisting} 57 | 58 | \subsubsection{距离:点到直线距离} 59 | result:点到直线最近点 60 | \begin{lstlisting}[language=c++] 61 | Point NPT(Point P, Line L) 62 | { 63 | Point result; 64 | double a, b, t; 65 | 66 | a = L.e.x-L.s.x; 67 | b = L.e.y-L.s.y; 68 | t = ((P.x-L.s.x)*a+(P.y-L.s.y)*b)/(a*a+b*b); 69 | 70 | result.x = L.s.x+a*t; 71 | result.y = L.s.y+b*t; 72 | return dist(P, result); 73 | } 74 | \end{lstlisting} 75 | 76 | \subsubsection{距离:点到线段距离} 77 | res:点到线段最近点 78 | \begin{lstlisting}[language=c++] 79 | Point NearestPointToLineSeg(Point P, Line L) 80 | { 81 | Point result; 82 | double a, b, t; 83 | 84 | a = L.e.x-L.s.x; 85 | b = L.e.y-L.s.y; 86 | t = ( (P.x-L.s.x)*a+(P.y-L.s.y)*b )/(a*a+b*b); 87 | 88 | if (t >= 0 && t <= 1) 89 | { 90 | result.x = L.s.x+a*t; 91 | result.y = L.s.y+b*t; 92 | } 93 | else 94 | { 95 | if (dist(P,L.s) < dist(P,L.e)) 96 | result = L.s; 97 | else 98 | result = L.e; 99 | } 100 | return result; 101 | } 102 | \end{lstlisting} 103 | 旧版 104 | \begin{lstlisting}[language=c++] 105 | double CalcDis(Point a,Point s,Point e) //点到线段距离 106 | { 107 | if (sgn((e-s)*(a-s)) < 0 || sgn((s-e)*(a-e)) < 0) 108 | return min(dist(a,s),dist(a,e)); 109 | return abs(((s-a)*(e-a))/dist(s-e)); 110 | } 111 | \end{lstlisting} 112 | 113 | \subsubsection{面积:多边形} 114 | 点按逆时针排序。 115 | \begin{lstlisting}[language=c++] 116 | double CalcArea(Point p[], int n) 117 | { 118 | double res = 0; 119 | for (int i = 0; i < n; i++) 120 | res += (p[i]*p[(i+1) % n])/2; 121 | return res; 122 | } 123 | \end{lstlisting} 124 | 125 | \subsubsection{判断:线段相交} 126 | \begin{lstlisting}[language=c++] 127 | bool inter(Line l1,Line l2) 128 | { 129 | return 130 | max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) && 131 | max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) && 132 | max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) && 133 | max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) && 134 | sgn((l2.s-l1.s)*(l1.e-l1.s))*sgn((l2.e-l1.s)*(l1.e-l1.s)) <= 0 && 135 | sgn((l1.s-l2.s)*(l2.e-l2.s))*sgn((l1.e-l2.s)*(l2.e-l2.s)) <= 0; 136 | } 137 | \end{lstlisting} 138 | 139 | \subsubsection{判断:点在线段上} 140 | \begin{lstlisting}[language=c++] 141 | bool OnSeg(Line a,Point b) 142 | { 143 | return ((a.s-b)*(a.e-b) == 0 && 144 | (b.x-a.s.x)*(b.x-a.e.x) <= 0 && 145 | (b.y-a.s.y)*(b.y-a.e.y) <= 0); 146 | } 147 | \end{lstlisting} 148 | 149 | \subsubsection{判断:点在多边形内} 150 | 凸包且按逆时针排序 151 | \begin{lstlisting}[language=c++] 152 | bool inPoly(Point a,Point p[],int n) 153 | { 154 | for (int i = 0;i < n;i++) 155 | if ((p[i]-a)*(p[(i+1)%n]-a) < 0) 156 | return false; 157 | return true; 158 | } 159 | \end{lstlisting} 160 | 射线法, 多边形可以是凸的或凹的\\ 161 | poly的顶点数目要大于等于3\\ 162 | 返回值为:\\ 163 | 0 -- 点在poly内\\ 164 | 1 -- 点在poly边界上\\ 165 | 2 -- 点在poly外 166 | \begin{lstlisting}[language=c++] 167 | int inPoly(Point p,Point poly[], int n) 168 | { 169 | int i, count; 170 | Line ray, side; 171 | 172 | count = 0; 173 | ray.s = p; 174 | ray.e.y = p.y; 175 | ray.e.x = -1;//`-INF,注意取值防止越界!` 176 | 177 | for (i = 0; i < n; i++) 178 | { 179 | side.s = poly[i]; 180 | side.e = poly[(i+1)%n]; 181 | 182 | if(OnSeg(p, side)) 183 | return 1; 184 | 185 | // 如果side平行x轴则不作考虑 186 | if (side.s.y == side.e.y) 187 | continue; 188 | 189 | if (OnSeg(side.s, ray)) 190 | { 191 | if (side.s.y > side.e.y) count++; 192 | } 193 | else if (OnSeg(side.e, ray)) 194 | { 195 | if (side.e.y > side.s.y) count++; 196 | } 197 | else if (inter(ray, side)) 198 | { 199 | count++; 200 | } 201 | } 202 | return ((count % 2 == 1) ? 0 : 2); 203 | } 204 | \end{lstlisting} 205 | 206 | \subsubsection{判断:两凸包相交} 207 | 需要考虑这几个:一个凸包的点在另外一个图包内(包括边界);一个凸包的某条边与另一个凸包某条边相交;如果凸包可能退化成点线还需要判断点在线段上和点和点重合。 208 | 209 | \subsubsection{排序:叉积极角排序} 210 | \begin{lstlisting}[language=c++] 211 | bool cmp(const Point& a,const Point& b) 212 | { 213 | if (a.y*b.y <= 0) 214 | { 215 | if (a.y > 0 || b.y > 0) return a.y < b.y; 216 | if (a.y == 0 && b.y == 0) return a.x < b.x; 217 | } 218 | return a*b > 0; 219 | } 220 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/center.tex: -------------------------------------------------------------------------------- 1 | \subsection{重心} 2 | \begin{lstlisting}[language=c++] 3 | Point CenterOfPolygon(Point poly[],int n) 4 | { 5 | Point p, p0, p1, p2, p3; 6 | double m, m0; 7 | p1 = poly[0]; 8 | p2 = poly[1]; 9 | p.x = p.y = m = 0; 10 | for (int i = 2; i < n; i++) 11 | { 12 | p3 = poly[i]; 13 | p0.x = (p1.x + p2.x + p3.x) / 3.0; 14 | p0.y = (p1.y + p2.y + p3.y) / 3.0; 15 | m0 = p1.x*p2.y+p2.x*p3.y+p3.x*p1.y-p1.y*p2.x-p2.y*p3.x-p3.y*p1.x; 16 | if (cmp(m + m0,0.0) == 0) 17 | m0 += eps; 18 | p.x = (m * p.x + m0 * p0.x) / (m + m0); 19 | p.y = (m * p.y + m0 * p0.y) / (m + m0); 20 | m = m + m0; 21 | p2 = p3; 22 | } 23 | return p; 24 | } 25 | \end{lstlisting} 26 | -------------------------------------------------------------------------------- /geometric/circle.tex: -------------------------------------------------------------------------------- 1 | \subsection{圆} 2 | \subsubsection{面积:两圆相交} 3 | 圆不可包含 4 | \begin{lstlisting}[language=c++] 5 | double dis(int x,int y) 6 | { 7 | return sqrt((double)(x*x+y*y)); 8 | } 9 | double area(int x1,int y1,int x2,int y2,double r1,double r2) 10 | { 11 | double s=dis(x2-x1,y2-y1); 12 | if(r1+r2s) return PI*r1*r1; 14 | else if(r1-r2>s) return PI*r2*r2; 15 | double q1=acos((r1*r1+s*s-r2*r2)/(2*r1*s)); 16 | double q2=acos((r2*r2+s*s-r1*r1)/(2*r2*s)); 17 | return (r1*r1*q1+r2*r2*q2-r1*s*sin(q1)); 18 | } 19 | \end{lstlisting} 20 | 21 | \subsubsection{三角形外接圆} 22 | \begin{lstlisting}[language=c++] 23 | void CircumscribedCircle() 24 | { 25 | for (int i = 0; i < 3; i++) 26 | scanf("%lf%lf",&p[i].x,&p[i].y); 27 | tp = Point((p[0].x+p[1].x)/2,(p[0].y+p[1].y)/2); 28 | l[0] = Line(tp,Point(tp.x-(p[1].y-p[0].y),tp.y+(p[1].x-p[0].x))); 29 | tp = Point((p[0].x+p[2].x)/2,(p[0].y+p[2].y)/2); 30 | l[1] = Line(tp,Point(tp.x-(p[2].y-p[0].y),tp.y+(p[2].x-p[0].x))); 31 | tp = LineToLine(l[0],l[1]); 32 | r = Point(tp,p[0]).Length(); 33 | printf("(%.6f,%.6f,%.6f)\n",tp.x,tp.y,r); 34 | } 35 | \end{lstlisting} 36 | 37 | \subsubsection{三角形内切圆} 38 | \begin{lstlisting}[language=c++] 39 | void InscribedCircle() 40 | { 41 | for (int i = 0; i < 3; i++) 42 | scanf("%lf%lf",&p[i].x,&p[i].y); 43 | if (xmult(Point(p[0],p[1]),Point(p[0],p[2])) < 0) 44 | swap(p[1],p[2]); 45 | for (int i = 0; i < 3; i++) 46 | len[i] = Point(p[i],p[(i+1)%3]).Length(); 47 | tr = (len[0]+len[1]+len[2])/2; 48 | r = sqrt((tr-len[0])*(tr-len[1])*(tr-len[2])/tr); 49 | for (int i = 0; i < 2; i++) 50 | { 51 | v = Point(p[i],p[i+1]); 52 | tv = Point(-v.y,v.x); 53 | tr = tv.Length(); 54 | tv = Point(tv.x*r/tr,tv.y*r/tr); 55 | tp = Point(p[i].x+tv.x,p[i].y+tv.y); 56 | l[i].s = tp; 57 | tp = Point(p[i+1].x+tv.x,p[i+1].y+tv.y); 58 | l[i].e = tp; 59 | } 60 | tp = LineToLine(l[0],l[1]); 61 | printf("(%.6f,%.6f,%.6f)\n",tp.x,tp.y,r); 62 | } 63 | \end{lstlisting} 64 | 65 | \subsubsection{点对圆的两个切点} 66 | \begin{lstlisting}[language=c++] 67 | void calc_qie(Point poi,Point o,double r,Point &result1,Point &result2) 68 | { 69 | double line = sqrt((poi.x-o.x)*(poi.x-o.x)+(poi.y-o.y)*(poi.y-o.y)); 70 | double angle = acos(r/line); 71 | Point unitvector,lin; 72 | lin.x = poi.x-o.x; 73 | lin.y = poi.y-o.y; 74 | unitvector.x = lin.x/sqrt(lin.x*lin.x+lin.y*lin.y)*r; 75 | unitvector.y = lin.y/sqrt(lin.x*lin.x+lin.y*lin.y)*r; 76 | result1 = unitvector.Rotate(-angle); 77 | result2 = unitvector.Rotate(angle); 78 | result1.x += o.x; 79 | result1.y += o.y; 80 | result2.x += o.x; 81 | result2.y += o.y; 82 | } 83 | \end{lstlisting} 84 | 85 | \subsubsection{两圆公切点} 86 | \begin{lstlisting}[language=c++] 87 | void Gao() 88 | { 89 | tn = 0; 90 | Point a,b,vab; 91 | double tab,tt,dis,theta; 92 | for (int i = 0; i < tc; i++) 93 | for (int j = 0; j < tc; j++) 94 | if (i != j) 95 | { 96 | a = c[i]; 97 | b = c[j]; 98 | vab = Point(a,b); 99 | tab = atan2(vab.y,vab.x); 100 | dis = sqrt(vab.x*vab.x+vab.y*vab.y); 101 | if (b.r > a.r) 102 | tt = asin((b.r-a.r)/dis); 103 | else 104 | tt = -asin((a.r-b.r)/dis); 105 | theta = tab+pi/2+tt; 106 | tp[tn++] = Point(a.x+a.r*cos(theta),a.y+a.r*sin(theta)); 107 | tp[tn++] = Point(b.x+b.r*cos(theta),b.y+b.r*sin(theta)); 108 | } 109 | } 110 | \end{lstlisting} 111 | 112 | \subsubsection{两圆交点} 113 | \begin{lstlisting}[language=c++] 114 | lab = Point(p[j].x-p[i].x,p[j].y-p[i].y); 115 | AB = lab.Length(); 116 | AC = cr[i]; 117 | BC = cr[j]; 118 | 119 | if (cmp(AB+AC,BC) <= 0) continue;//包含 120 | if (cmp(AB+BC,AC) <= 0) continue; 121 | if (cmp(AB,AC+BC) > 0) continue;//相离 122 | 123 | theta = atan2(lab.y,lab.x); 124 | fai = acos((AC*AC+AB*AB-BC*BC)/(2.0*AC*AB)); 125 | a0 = theta-fai; 126 | if (cmp(a0,-pi) < 0) a0 += 2*pi; 127 | a1 = theta+fai; 128 | if (cmp(a1,pi) > 0) a1 -= 2*pi; 129 | //答案 130 | xp[totp++] = Point(p[i].x+cr[i]*cos(a0),p[i].y+cr[i]*sin(a0)); 131 | xp[totp++] = Point(p[i].x+cr[i]*cos(a1),p[i].y+cr[i]*sin(a1)); 132 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/circleandpoly.tex: -------------------------------------------------------------------------------- 1 | \subsection{一个圆与多边形面积交} 2 | \begin{lstlisting}[language=c++] 3 | bool InCircle(Point a,double r) 4 | { 5 | return cmp(a.x*a.x+a.y*a.y,r*r) <= 0; 6 | //`这里判断的时候EPS一定不要太小!!` 7 | } 8 | 9 | double CalcArea(Point a,Point b,double r) 10 | { 11 | Point p[4]; 12 | int tot = 0; 13 | p[tot++] = a; 14 | 15 | Point tv = Point(a,b); 16 | Line tmp = Line(Point(0,0),Point(tv.y,-tv.x)); 17 | Point near = LineToLine(Line(a,b),tmp); 18 | if (cmp(near.x*near.x+near.y*near.y,r*r) <= 0) 19 | { 20 | double A,B,C; 21 | A = near.x*near.x+near.y*near.y; 22 | C = r; 23 | B = C*C-A; 24 | double tvl = tv.x*tv.x+tv.y*tv.y; 25 | double tmp = sqrt(B/tvl); //这样做只用一次开根 26 | p[tot] = Point(near.x+tmp*tv.x,near.y+tmp*tv.y); 27 | if (OnSeg(Line(a,b),p[tot]) == true) tot++; 28 | p[tot] = Point(near.x-tmp*tv.x,near.y-tmp*tv.y); 29 | if (OnSeg(Line(a,b),p[tot]) == true) tot++; 30 | } 31 | if (tot == 3) 32 | { 33 | if (cmp(Point(p[0],p[1]).Length(),Point(p[0],p[2]).Length()) > 0) 34 | swap(p[1],p[2]); 35 | } 36 | p[tot++] = b; 37 | 38 | double res = 0.0,theta,a0,a1,sgn; 39 | for (int i = 0;i < tot-1;i++) 40 | { 41 | if (InCircle(p[i],r) == true && InCircle(p[i+1],r) == true) 42 | { 43 | res += 0.5*xmult(p[i],p[i+1]); 44 | } 45 | else 46 | { 47 | a0 = atan2(p[i+1].y,p[i+1].x); 48 | a1 = atan2(p[i].y,p[i].x); 49 | if (a0 < a1) a0 += 2*pi; 50 | theta = a0-a1; 51 | if (cmp(theta,pi) >= 0) theta = 2*pi-theta; 52 | sgn = xmult(p[i],p[i+1])/2.0; 53 | if (cmp(sgn,0) < 0) theta = -theta; 54 | res += 0.5*r*r*theta; 55 | } 56 | } 57 | return res; 58 | } 59 | \end{lstlisting} 60 | 调用 61 | \begin{lstlisting}[language=c++] 62 | area2 = 0.0; 63 | for (int i = 0;i < resn;i++) //遍历每条边,按照逆时针 64 | area2 += CalcArea(p[i],p[(i+1)%resn],r); 65 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/eps.tex: -------------------------------------------------------------------------------- 1 | \subsection{精度问题} 2 | \subsubsection{浮点数为啥会有精度问题} 3 | 浮点数(以C/C++为准),一般用的较多的是float、double。\\ 4 | \begin{table}[htbp] 5 | \centering 6 | \begin{tabular}{l|l|l|l} 7 | \toprule 8 | &占字节数&数值范围&十进制精度位数\\ 9 | \midrule 10 | float&$4$&$-3.4e-38\sim 3.4e38$&$6\sim 7$\\ 11 | double&$8$&$-1.7e-308\sim 1.7e308$&$14\sim 15$\\ 12 | \bottomrule 13 | \end{tabular} 14 | \end{table} 15 | ~\\ 16 | 如果内存不是很紧张或者精度要求不是很低,一般选用double。$14$位的精度(是有效数字位,不是小数点后的位数)通常够用了。注意,问题来了,数据精度位数达到了$14$位,但有些浮点运算的结果精度并达不到这么高,可能准确的结果只有$10\sim 12$位左右。那低几位呢?自然就是不可预料的数字了。这给我们带来这样的问题:即使是理论上相同的值,由于是经过不同的运算过程得到的,他们在低几位有可能(一般来说都是)是不同的。这种现象看似没太大的影响,却会一种运算产生致命的影响:$==$。恩,就是判断相等。注意,C/C++中浮点数的==需要完全一样才能返回true。\\ 17 | 18 | \subsubsection{eps} 19 | eps缩写自epsilon,表示一个小量,但这个小量又要确保远大于浮点运算结果的不确定量。eps最常见的取值是$1e-8$左右。引入eps后,我们判断两浮点数a、b相等的方式如下: 20 | \begin{lstlisting}[language=c++] 21 | int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;} 22 | \end{lstlisting} 23 | 这样,我们才能把相差非常近的浮点数判为相等;同时把确实相差较大(差值大于eps)的数判为不相等。\\ 24 | 养成好习惯,尽量不要再对浮点数做$==$判断。\\ 25 | 26 | \subsubsection{eps带来的函数越界} 27 | 如果sqrt(a), asin(a), acos(a) 中的a是你自己算出来并传进来的,那就得小心了。\\ 28 | 如果a本来应该是$0$的,由于浮点误差,可能实际是一个绝对值很小的负数(比如$-1e-12$),这样sqrt(a)应得$0$的,直接因a不在定义域而出错。\\ 29 | 类似地,如果a本来应该是$\pm 1$,则asin(a)、acos(a)也有可能出错。\\ 30 | 因此,对于此种函数,必需事先对a进行校正。\\ 31 | 32 | \subsubsection{输出陷阱I} 33 | 现在考虑一种情况,题目要求输出保留两位小数。有个case的正确答案的精确值是$0.005$,按理应该输出$0.01$,但你的结果可能是$0.005000000001$(恭喜),也有可能是$0.004999999999$(悲剧),如果按照\textsf{printf(“\%.2lf”, a)}输出,那你的遭遇将和括号里的字相同。\\ 34 | 解决办法是,如果$a$为正,则输出$a+eps$, 否则输出$a-eps$\\ 35 | 36 | \subsubsection{输出陷阱II} 37 | ICPC题目输出有个不成文的规定(有时也成文),不要输出:$-0.000$\\ 38 | 那我们首先要弄清,什么时候按\textsf{printf(“\%.3lf”, a)}输出会出现这个结果。\\ 39 | 直接给出结果好了:$a\in (-0.000499999\cdots , -0.000\cdots 1)$\\ 40 | 所以,如果你发现a落在这个范围内,请直接输出$0.000$。更保险的做法是用\textsf{sprintf}直接判断输出结果是不是$-0.000$再予处理。\\ 41 | 42 | \subsubsection{范围越界} 43 | 请注意,虽然double可以表示的数的范围很大,却不是不穷大,上面说过最大是$1e308$。所以有些时候你得小心了,比如做连乘的时候,必要的时候要换成对数的和。\\ 44 | 45 | \subsubsection{关于set} 46 | 经观察,set不是通过$==$来判断相等的,是通过$<$来进行的,具体说来,只要$a atan2(p2.y, p2.x)) 19 | swap(b, c); 20 | if ((p[b] - p[a]) * (p[c] - p[a]) > 0) 21 | return cnt[a][c] - cnt[a][b] - 1; 22 | else 23 | return n - 3 - (cnt[a][c] - cnt[a][b] - 1); 24 | } 25 | 26 | int main(int argc, char const *argv[]) 27 | { 28 | int totcas; 29 | scanf("%d", &totcas); 30 | for (int cas = 1; cas <= totcas; ++cas) 31 | { 32 | scanf("%d", &n); 33 | for (int i = 0; i < n; ++i) 34 | { 35 | scanf("%lld%lld", &p[i].x, &p[i].y); 36 | p[i].id = i; 37 | } 38 | for (int i = 0; i < n; ++i) 39 | { 40 | m = 0; 41 | base = p[i]; 42 | for (int j = 0; j < n; ++j) 43 | if (i != j) 44 | { 45 | tp[m] = p[j]; 46 | Point v = tp[m]-base; 47 | tp[m++].theta = atan2(v.y,v.x); 48 | } 49 | 50 | sort(tp, tp + m, cmp); 51 | for (int j = 0; j < m; ++j) 52 | tp[m + j] = tp[j]; 53 | 54 | //calc cnt 55 | for (int j = 0; j < m; ++j) 56 | cnt[i][tp[j].id] = j; 57 | 58 | //calc cntleft 59 | for (int j = 0, k = 0, tot = 0; j < m; ++j) 60 | { 61 | while (k == j || (k < j + m && (tp[j] - base) * (tp[k] - base) > 0)) 62 | k++, tot++; 63 | cntleft[i][tp[j].id] = --tot; 64 | } 65 | } 66 | 67 | printf("Case %d:\n", cas); 68 | int q; 69 | scanf("%d", &q); 70 | for (int i = 0; i < q; ++i) 71 | { 72 | int x, y, z; 73 | scanf("%d%d%d", &x, &y, &z); 74 | if ((p[z] - p[x]) * (p[y] - p[x]) > 0) 75 | swap(y, z); 76 | int res = cntleft[x][z] + cntleft[z][y] + cntleft[y][x]; 77 | res += calc(x, y, z) + calc(y, z, x) + calc(z, x, y); 78 | res -= 2 * (n - 3); 79 | printf("%d\n", res); 80 | } 81 | } 82 | return 0; 83 | } 84 | \end{lstlisting} 85 | 86 | \subsubsection{有三点共线且点有类别之分} 87 | \begin{lstlisting}[language=c++] 88 | int n,n0,n1,m; 89 | Point p[3000], tp[3000], base; 90 | 91 | bool cmp(const Point &a, const Point &b) 92 | { 93 | if ((a-base)*(b-base) == 0) 94 | { 95 | return (a-base).getMol() < (b-base).getMol(); 96 | } 97 | return a.theta < b.theta; 98 | } 99 | 100 | int cnt[100][100]; 101 | int cntleft[100][100]; 102 | 103 | int calc(int a,int b,int c) 104 | { 105 | Point p1 = p[b]-p[a],p2 = p[c]-p[a]; 106 | if (atan2(1.0*p1.y,1.0*p1.x) > atan2(1.0*p2.y,1.0*p2.x)) 107 | swap(b,c); 108 | int res = cnt[a][c]-cnt[a][b]; 109 | if ((p[b]-p[a])*(p[c]-p[a]) > 0) 110 | return res; 111 | else 112 | return n1-res; 113 | } 114 | 115 | int main() 116 | { 117 | int cas = 0; 118 | while (scanf("%d%d",&n0,&n1) != EOF) 119 | { 120 | n = n1+n0; 121 | for (int i = 0; i < n; i++) 122 | { 123 | scanf("%I64d%I64d",&p[i].x,&p[i].y); 124 | p[i].id = i; 125 | } 126 | for (int i = 0; i < n0; ++i) 127 | { 128 | m = 0; 129 | base = p[i]; 130 | for (int j = 0; j < n; ++j) 131 | if (i != j) 132 | { 133 | tp[m] = p[j]; 134 | Point v = tp[m]-base; 135 | tp[m++].theta = atan2(1.0*v.y,1.0*v.x); 136 | } 137 | 138 | sort(tp, tp + m, cmp); 139 | for (int j = 0; j < m; ++j) 140 | tp[m + j] = tp[j]; 141 | 142 | for (int j = 0,tot = 0; j < m; ++j) 143 | { 144 | if (tp[j].id < n0) 145 | cnt[i][tp[j].id] = tot; 146 | else 147 | tot++; 148 | } 149 | 150 | for (int j = 0, k = 0, tot = 0; j < m; ++j) 151 | { 152 | while (k == j || (k < j + m && (tp[j] - base) * (tp[k] - base) > 0)) 153 | { 154 | if (tp[k].id >= n0) 155 | tot++; 156 | k++; 157 | } 158 | if (tp[j].id >= n0) 159 | tot--; 160 | else 161 | cntleft[i][tp[j].id] = tot; 162 | } 163 | } 164 | 165 | int ans = 0; 166 | for (int i = 0; i < n0; i++) 167 | for (int j = i+1; j < n0; j++) 168 | for (int k = j+1; k < n0; k++) 169 | { 170 | int x = i,y = j,z = k; 171 | 172 | if ((p[z] - p[x]) * (p[y] - p[x]) > 0) 173 | swap(y, z); 174 | int res = cntleft[x][z] + cntleft[z][y] + cntleft[y][x]; 175 | 176 | res += calc(x, y, z) + calc(y, z, x) + calc(z, x, y); 177 | 178 | res -= 2 * n1; 179 | 180 | //printf("%d %d %d %d\n",x,y,z,res); 181 | 182 | if (res%2 == 1) 183 | ans++; 184 | } 185 | printf("Case %d: %d\n",++cas,ans); 186 | } 187 | return 0; 188 | } 189 | \end{lstlisting} 190 | -------------------------------------------------------------------------------- /geometric/intersectionbetweenlineandconvexhull.tex: -------------------------------------------------------------------------------- 1 | \subsection{直线与凸包求交点} 2 | 复杂度$O(\log{n})$。\\ 3 | 需要先预处理几个东西。\\ 4 | \begin{lstlisting}[language=c++] 5 | //`二分[la,lb]这段区间那条边与line相交` 6 | int Gao(int la,int lb,Line line) 7 | { 8 | if (la > lb) 9 | lb += n; 10 | int l = la,r = lb,mid; 11 | while (l < r) 12 | { 13 | mid = l+r+1>>1; 14 | if (cmp((line.e-line.s)*(p[la]-line.s),0)*cmp((line.e-line.s)*(p[mid]-line.s),0) >= 0) 15 | l = mid; 16 | else 17 | r = mid-1; 18 | } 19 | return l%n; 20 | } 21 | //`求l与凸包的交点` 22 | 23 | //`先调用Gettheta预处理出凸包每条边的斜率,然后处理成升序排列` 24 | double theta[maxn]; 25 | 26 | void Gettheta() 27 | { 28 | for (int i = 0;i < n;i++) 29 | { 30 | Point v = p[(i+1)%n]-p[i]; 31 | theta[i] = atan2(v.y,v.x); 32 | } 33 | for (int i = 1;i < n;i++) 34 | if (theta[i-1] > theta[i]+eps) 35 | theta[i] += 2*pi; 36 | } 37 | 38 | double Calc(Line l) 39 | { 40 | double tnow; 41 | Point v = l.e-l.s; 42 | tnow = atan2(v.y,v.x); 43 | if (cmp(tnow,theta[0]) < 0) tnow += 2*pi; 44 | int pl = lower_bound(theta,theta+n,tnow)-theta; 45 | tnow = atan2(-v.y,-v.x); 46 | if (cmp(tnow,theta[0]) < 0) tnow += 2*pi; 47 | int pr = lower_bound(theta,theta+n,tnow)-theta; 48 | //`pl和pr是在l方向上距离最远的点对` 49 | pl = pl%n; 50 | pr = pr%n; 51 | 52 | if (cmp(v*(p[pl]-l.s),0)*cmp(v*(p[pr]-l.s),0) >= 0) 53 | return 0.0; 54 | 55 | int xa = Gao(pl,pr,l); 56 | int xb = Gao(pr,pl,l); 57 | 58 | if (xa > xb) swap(xa,xb); 59 | //`与[xa,xa+1]和[xb,xb+1]`这两条线段相交 60 | 61 | if (cmp(v*(p[xa+1]-p[xa]),0) == 0) return 0.0; 62 | if (cmp(v*(p[xb+1]-p[xb]),0) == 0) return 0.0; 63 | 64 | Point pa,pb; 65 | pa = Line(p[xa],p[xa+1])&l; 66 | pb = Line(p[xb],p[xb+1])&l; 67 | //`题目:求直线切凸包得到的两部分的面积` 68 | double area0 = sum[xb]-sum[xa+1]+(pa*p[xa+1])/2.0+(p[xb]*pb)/2.0+(pb*pa)/2.0; 69 | double area1 = sum[xa+n]-sum[xb+1]+(pb*p[xb+1])/2.0+(p[xa]*pa)/2.0+(pa*pb)/2.0; 70 | 71 | return min(area0,area1); 72 | } 73 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/matrix.tex: -------------------------------------------------------------------------------- 1 | \subsection{矩阵} 2 | \subsubsection{基本矩阵} 3 | 按向量$\overrightarrow{(x,y,z)}$平移: 4 | \[\begin{pmatrix} 5 | 1 & 0 & 0 & x\\ 6 | 0 & 1 & 0 & y\\ 7 | 0 & 0 & 1 & z\\ 8 | 0 & 0 & 0 & 1 9 | \end{pmatrix}\]\\ 10 | \\ 11 | 按比例$(x,y,z)$缩放: 12 | \[\begin{pmatrix} 13 | x & 0 & 0 & 0\\ 14 | 0 & y & 0 & 0\\ 15 | 0 & 0 & z & 0\\ 16 | 0 & 0 & 0 & 1 17 | \end{pmatrix}\]\\ 18 | \\ 19 | 绕单位向量$\overrightarrow{(x,y,z)}$旋转$angle$角度: 20 | \[\begin{pmatrix} 21 | x^2\times (1-c)+c & x\times y\times (1-c)-z\times s & x\times z\times (1-c)+y\times s & 0\\ 22 | y\times x\times (1-c)+z\times s & y^2\times (1-c)+c & y\times z\times (1-c)-x\times s & 0\\ 23 | x\times z\times (1-c)-y\times s & y\times z\times (1-c)+x\times s & z^2\times (1-c)+c & 0\\ 24 | 0 & 0 & 0 & 1 25 | \end{pmatrix} 26 | \begin{cases} 27 | s=sin(angle)\\ 28 | c=cos(angle) 29 | \end{cases}\] 30 | 以上矩阵变换都把点当作列向量,旋转角度的正负由右手定则决定\\ 31 | 32 | \subsubsection{刘汝佳的几何教室} 33 | \begin{lstlisting}[language=c++] 34 | const double pi = acos(-1.0); 35 | 36 | int n,m,q; 37 | struct Point 38 | { 39 | double a,b,c,d; 40 | }; 41 | Point p[50000],f[50000]; 42 | 43 | double a,b,c,theta,mt[4][4],tmp[4][4],tmt[4][4],rmt[4][8]; 44 | char com[20]; 45 | 46 | void TRANSLATE() 47 | { 48 | memset(tmt,0,sizeof(tmt)); 49 | tmt[0][0] = tmt[1][1] = tmt[2][2] = tmt[3][3] = 1; 50 | tmt[3][0] = a; 51 | tmt[3][1] = b; 52 | tmt[3][2] = c; 53 | memset(tmp,0,sizeof(tmp)); 54 | for (int i = 0; i < 4; i++) 55 | for (int j = 0; j < 4; j++) 56 | for (int k = 0; k < 4; k++) 57 | tmp[i][j] += mt[i][k]*tmt[k][j]; 58 | for (int i = 0; i < 4; i++) 59 | for (int j = 0; j < 4; j++) 60 | mt[i][j] = tmp[i][j]; 61 | } 62 | 63 | void ROTATE() 64 | { 65 | theta = -theta*pi/180; 66 | memset(tmt,0,sizeof(tmt)); 67 | tmt[3][3] = 1; 68 | tmt[0][0] = cos(theta)+(1-cos(theta))*a*a; 69 | tmt[1][0] = (1-cos(theta))*a*b+c*sin(theta); 70 | tmt[2][0] = (1-cos(theta))*a*c-b*sin(theta); 71 | tmt[0][1] = (1-cos(theta))*a*b-c*sin(theta); 72 | tmt[1][1] = cos(theta)+(1-cos(theta))*b*b; 73 | tmt[2][1] = (1-cos(theta))*b*c+a*sin(theta); 74 | tmt[0][2] = (1-cos(theta))*a*c+b*sin(theta); 75 | tmt[1][2] = (1-cos(theta))*b*c-a*sin(theta); 76 | tmt[2][2] = cos(theta)+(1-cos(theta))*c*c; 77 | memset(tmp,0,sizeof(tmp)); 78 | for (int i = 0; i < 4; i++) 79 | for (int j = 0; j < 4; j++) 80 | for (int k = 0; k < 4; k++) 81 | tmp[i][j] += mt[i][k]*tmt[k][j]; 82 | for (int i = 0; i < 4; i++) 83 | for (int j = 0; j < 4; j++) 84 | mt[i][j] = tmp[i][j]; 85 | } 86 | 87 | void SCALE() 88 | { 89 | memset(tmt,0,sizeof(tmt)); 90 | tmt[0][0] = a; 91 | tmt[1][1] = b; 92 | tmt[2][2] = c; 93 | tmt[3][3] = 1; 94 | memset(tmp,0,sizeof(tmp)); 95 | for (int i = 0; i < 4; i++) 96 | for (int j = 0; j < 4; j++) 97 | for (int k = 0; k < 4; k++) 98 | tmp[i][j] += mt[i][k]*tmt[k][j]; 99 | for (int i = 0; i < 4; i++) 100 | for (int j = 0; j < 4; j++) 101 | mt[i][j] = tmp[i][j]; 102 | } 103 | 104 | void solvep(Point p) 105 | { 106 | memset(tmt,0,sizeof(tmt)); 107 | tmt[0][0] = p.a; 108 | tmt[0][1] = p.b; 109 | tmt[0][2] = p.c; 110 | tmt[0][3] = 1; 111 | memset(tmp,0,sizeof(tmp)); 112 | for (int i = 0; i < 1; i++) 113 | for (int j = 0; j < 4; j++) 114 | for (int k = 0; k < 4; k++) 115 | tmp[i][j] += tmt[i][k]*mt[k][j]; 116 | printf("%.2f %.2f %.2f\n",tmp[0][0],tmp[0][1],tmp[0][2]); 117 | } 118 | 119 | void solvef(Point f) 120 | { 121 | memset(tmt,0,sizeof(tmt)); 122 | tmt[0][0] = f.a; 123 | tmt[1][0] = f.b; 124 | tmt[2][0] = f.c; 125 | tmt[3][0] = 0; 126 | memset(tmp,0,sizeof(tmp)); 127 | for (int i = 0;i < 4;i++) 128 | for (int j = 0;j < 1;j++) 129 | for (int k = 0;k < 4;k++) 130 | tmp[i][j] += mt[i][k]*tmt[k][j]; 131 | tmp[3][0] += f.d; 132 | double kk = tmp[0][0]*tmp[0][0]+tmp[1][0]*tmp[1][0]+tmp[2][0]*tmp[2][0]; 133 | kk = sqrt(1/kk); 134 | for (int i = 0;i < 4;i++) 135 | printf("%.2f ",tmp[i][0]*kk); 136 | printf("\n"); 137 | } 138 | 139 | void solvermt() 140 | { 141 | memset(rmt,0,sizeof(rmt)); 142 | for (int i = 0;i < 4;i++) 143 | for (int j = 0;j < 4;j++) 144 | rmt[i][j] = mt[i][j]; 145 | rmt[0][4] = rmt[1][5] = rmt[2][6] = rmt[3][7] = 1; 146 | for (int i = 0;i < 4;i++) 147 | { 148 | for (int j = i;j < 4;j++) 149 | if (fabs(rmt[j][i]) > 1e-8) 150 | { 151 | for (int k = i;k < 8;k++) 152 | swap(rmt[i][k],rmt[j][k]); 153 | break; 154 | } 155 | double tt = rmt[i][i]; 156 | for (int j = i;j < 8;j++) 157 | rmt[i][j] /= tt; 158 | for (int j = 0;j < 4;j++) 159 | if (i != j) 160 | { 161 | tt = rmt[j][i]; 162 | for (int k = i;k < 8;k++) 163 | rmt[j][k] -= rmt[i][k]*tt; 164 | } 165 | } 166 | for (int i = 0;i < 4;i++) 167 | for (int j = 0;j < 4;j++) 168 | mt[i][j] = rmt[i][4+j]; 169 | } 170 | 171 | int main() 172 | { 173 | scanf("%d%d%d",&n,&m,&q); 174 | for (int i = 0; i < n; i++) 175 | scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].c); 176 | for (int i = 0; i < m; i++) 177 | scanf("%lf%lf%lf%lf",&f[i].a,&f[i].b,&f[i].c,&f[i].d); 178 | memset(mt,0,sizeof(mt)); 179 | mt[0][0] = mt[1][1] = mt[2][2] = mt[3][3] = 1; 180 | for (int i = 0; i < q; i++) 181 | { 182 | scanf("%s",com); 183 | if (strcmp(com,"TRANSLATE") == 0) 184 | { 185 | scanf("%lf%lf%lf",&a,&b,&c); 186 | TRANSLATE(); 187 | } 188 | else if (strcmp(com,"ROTATE") == 0) 189 | { 190 | scanf("%lf%lf%lf%lf",&a,&b,&c,&theta); 191 | ROTATE(); 192 | } 193 | else if (strcmp(com,"SCALE") == 0) 194 | { 195 | scanf("%lf%lf%lf",&a,&b,&c); 196 | SCALE(); 197 | } 198 | } 199 | //处理点 200 | for (int i = 0; i < n; i++) 201 | solvep(p[i]); 202 | //处理面 203 | solvermt(); 204 | for (int i = 0; i < m; i++) 205 | solvef(f[i]); 206 | return 0; 207 | } 208 | \end{lstlisting} 209 | -------------------------------------------------------------------------------- /geometric/nearsetpoints.tex: -------------------------------------------------------------------------------- 1 | \subsection{最近点对} 2 | \subsubsection{类快排算法} 3 | \begin{lstlisting}[language=c++] 4 | double calc_dis(Point &a ,Point &b) { 5 | return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); 6 | } 7 | //别忘了排序 8 | bool operator<(const Point &a ,const Point &b) { 9 | if(a.y != b.y) return a.x < b.x; 10 | return a.x < b.x; 11 | } 12 | double Gao(int l ,int r ,Point pnts[]) { 13 | double ret = inf; 14 | if(l == r) return ret; 15 | if(l+1 ==r) { 16 | ret = min(calc_dis(pnts[l],pnts[l+1]) ,ret); 17 | return ret; 18 | } 19 | if(l+2 ==r) { 20 | ret = min(calc_dis(pnts[l],pnts[l+1]) ,ret); 21 | ret = min(calc_dis(pnts[l],pnts[l+2]) ,ret); 22 | ret = min(calc_dis(pnts[l+1],pnts[l+2]) ,ret); 23 | return ret; 24 | } 25 | 26 | int mid = l+r>>1; 27 | ret = min (ret ,Gao(l ,mid,pnts)); 28 | ret = min (ret , Gao(mid+1, r,pnts)); 29 | 30 | for(int c = l ; c<=r; c++) 31 | for(int d = c+1; d <=c+7 && d<=r; d++) { 32 | ret = min(ret , calc_dis(pnts[c],pnts[d])); 33 | } 34 | return ret; 35 | } 36 | \end{lstlisting} 37 | 38 | \subsubsection{随机增量法} 39 | \begin{lstlisting}[language=c++] 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #define Point pair 48 | using namespace std; 49 | 50 | const int step[9][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,0},{0,1},{1,-1},{1,0},{1,1}}; 51 | int n,x,y,nx,ny; 52 | map,vector > g; 53 | vector tmp; 54 | Point p[20000]; 55 | double tx,ty,ans,nowans; 56 | vector::iterator it,op,ed; 57 | pair gird; 58 | bool flag; 59 | 60 | double Dis(Point p0,Point p1) 61 | { 62 | return sqrt((p0.first-p1.first)*(p0.first-p1.first)+ 63 | (p0.second-p1.second)*(p0.second-p1.second)); 64 | } 65 | 66 | double CalcDis(Point p0,Point p1,Point p2) 67 | { 68 | return Dis(p0,p1)+Dis(p0,p2)+Dis(p1,p2); 69 | } 70 | 71 | void build(int n,double w) 72 | { 73 | g.clear(); 74 | for (int i = 0;i < n;i++) 75 | g[make_pair((int)floor(p[i].first/w),(int)floor(p[i].second/w))].push_back(p[i]); 76 | } 77 | 78 | int main() 79 | { 80 | int t; 81 | scanf("%d",&t); 82 | for (int ft = 1;ft <= t;ft++) 83 | { 84 | scanf("%d",&n); 85 | for (int i = 0;i < n;i++) 86 | { 87 | scanf("%lf%lf",&tx,&ty); 88 | p[i] = make_pair(tx,ty); 89 | } 90 | random_shuffle(p,p+n); 91 | ans = CalcDis(p[0],p[1],p[2]); 92 | build(3,ans/2.0); 93 | for (int i = 3;i < n;i++) 94 | { 95 | x = (int)floor(2.0*p[i].first/ans); 96 | y = (int)floor(2.0*p[i].second/ans); 97 | tmp.clear(); 98 | for (int k = 0;k < 9;k++) 99 | { 100 | nx = x+step[k][0]; 101 | ny = y+step[k][1]; 102 | gird = make_pair(nx,ny); 103 | if (g.find(gird) != g.end()) 104 | { 105 | op = g[gird].begin(); 106 | ed = g[gird].end(); 107 | for (it = op;it != ed;it++) 108 | tmp.push_back(*it); 109 | } 110 | } 111 | flag = false; 112 | for (int j = 0;j < tmp.size();j++) 113 | for (int k = j+1;k < tmp.size();k++) 114 | { 115 | nowans = CalcDis(p[i],tmp[j],tmp[k]); 116 | if (nowans < ans) 117 | { 118 | ans = nowans; 119 | flag = true; 120 | } 121 | } 122 | if (flag == true) 123 | build(i+1,ans/2.0); 124 | else 125 | g[make_pair((int)floor(2.0*p[i].first/ans),(int)floor(2.0*p[i].second/ans))].push_back(p[i]); 126 | } 127 | printf("%.3f\n",ans); 128 | } 129 | } 130 | \end{lstlisting} -------------------------------------------------------------------------------- /geometric/notice.tex: -------------------------------------------------------------------------------- 1 | \subsection{注意事项} 2 | 如果用整数小心越界(多次乘法?)\\ 3 | 如果用浮点数判断的时候一定要用eps!\\ 4 | -------------------------------------------------------------------------------- /geometric/pointtopoly.tex: -------------------------------------------------------------------------------- 1 | \subsection{点对凸包的两切点} 2 | 过了sgu500的前七组数据,用前需谨慎,虽然我不认为这个有问题。 3 | \begin{lstlisting}[language=c++] 4 | double theta[MaxN]; 5 | void Gettheta(Point p[],int n) 6 | { 7 | for (int i = 0;i < n;i++) 8 | { 9 | Point v = p[(i+1)%n]-p[i]; 10 | theta[i] = atan2(v.y,v.x); 11 | } 12 | for (int i = 1;i < n;i++) 13 | if (theta[i-1] > theta[i]+eps) 14 | theta[i] += 2*pi; 15 | } 16 | int cmp(double a,double b) 17 | { 18 | if (fabs(a-b) < eps) return 0; 19 | if (a < b) return -1; 20 | return 1; 21 | } 22 | int Gao(int la,int lb,Line line,Point p[],int n) 23 | { 24 | if (la > lb) 25 | lb += n; 26 | int l = la,r = lb,mid; 27 | while (l < r) 28 | { 29 | mid = l+r+1>>1; 30 | if (cmp((line.e-line.s)*(p[la%n]-line.s),0)*cmp((line.e-line.s)*(p[mid%n]-line.s),0) >= 0) 31 | l = mid; 32 | else 33 | r = mid-1; 34 | } 35 | return l%n; 36 | } 37 | int Gao(int la,int lb,int dir,Point s,Point p[],int n) 38 | { 39 | if (la > lb) 40 | lb += n; 41 | if (la == lb) return la; 42 | 43 | int l = la+1,r = lb,mid; 44 | 45 | while (l < r) 46 | { 47 | mid = l+r+1>>1; 48 | 49 | int ret = cmp((p[mid%n]-s)*(p[(mid-1)%n]-s),0); 50 | if (dir*ret < 0) 51 | l = mid; 52 | else if (dir*ret > 0) 53 | r = mid-1; 54 | else 55 | { 56 | if (dir == 1) 57 | l = mid; 58 | else 59 | r = mid-1; 60 | } 61 | } 62 | 63 | int ret = cmp((p[l%n]-s)*(p[(l-1)%n]-s),0); 64 | if (dir*ret < 0) 65 | return l%n; 66 | else if (dir*ret > 0) 67 | return (l-1)%n; 68 | else 69 | { 70 | if (dir == 1) 71 | return l%n; 72 | else 73 | return (l-1)%n; 74 | } 75 | } 76 | //Gettheta(p,n) first! 77 | //`返回S对于p[]的两个切点p[pl],p[pr]` 78 | void Calc(Point s,Point p[],int n,int& pl,int& pr) 79 | { 80 | Line l = Line(s,p[0]); 81 | Point v = l.e-l.s; 82 | double tnow = atan2(v.y,v.x); 83 | if (tnow < theta[0]-eps) tnow += 2*pi; 84 | int tpl = lower_bound(theta,theta+n,tnow)-theta; 85 | tnow = atan2(-v.y,-v.x); 86 | if (tnow < theta[0]-eps) tnow += 2*pi; 87 | int tpr = lower_bound(theta,theta+n,tnow)-theta; 88 | 89 | pl = tpl = tpl%n; 90 | pr = tpr = tpr%n; 91 | 92 | int px = Gao(pr,pl,l,p,n); 93 | //printf("pr = %d -> px = %d\n",tpr,px); 94 | //printf("px = %d -> pl = %d\n",px,tpl); 95 | //pr -> px 96 | //px -> pl 97 | 98 | pl = Gao(tpr,px,1,s,p,n); 99 | pr = Gao(px,tpl,-1,s,p,n); 100 | 101 | } 102 | \end{lstlisting} 103 | -------------------------------------------------------------------------------- /geometric/trangle.tex: -------------------------------------------------------------------------------- 1 | \subsection{三角形相关} 2 | \begin{description} 3 | \item[费马点:] 4 | 在$\triangle ABC$内求一点$P$,使$PA+PB+PC$之值为最小的点。当三角形有一个内角大于或等于$120$的时候,费马点就是该内角的顶点\\ 5 | 若没有,则费马点就是使得该点至三角形三顶点的连线两两夹角为$120$度的点.\\ 6 | \item[等角共轭点:] 7 | 对于三角形内任意一点$P$,过$A$做直线$L_1$与$AP$关于角$A$的角平分线对称,同样过$B$,$C$分别做$L_2$,$L_3$.这三条直线交于$P_1$,则$P_1$是$P$的等角共轭点.\\ 8 | 重心的等角共轭点到三边距离的平方和最小的点.\\ 9 | \end{description} 10 | -------------------------------------------------------------------------------- /graph.tex: -------------------------------------------------------------------------------- 1 | \section{图论} 2 | \input graph/dijkstra.tex 3 | \input graph/sap.tex 4 | \input graph/mcmf.tex 5 | \input graph/networksimplex.tex 6 | \input graph/match.tex 7 | \input graph/match2.tex 8 | \input graph/edmonds.tex 9 | \input graph/km.tex 10 | \input graph/planar.tex 11 | \input graph/sc.tex 12 | \input graph/clique.tex 13 | \input graph/bc.tex 14 | \input graph/cutbridge.tex 15 | \input graph/lca.tex 16 | \input graph/bestmst.tex 17 | \input graph/CountSpanningTrees.tex 18 | \input graph/sw.tex 19 | \input graph/euler.tex 20 | \input graph/kthpath.tex 21 | \input graph/marry.tex 22 | \input graph/zhuliu.tex 23 | -------------------------------------------------------------------------------- /graph/CountSpanningTrees.tex: -------------------------------------------------------------------------------- 1 | \subsection{生成树计数} 2 | 根据邻接矩阵构造Laplacian matrix。 3 | \begin{lstlisting}[language=c++] 4 | Matrix laplacian; 5 | laplacian.clear(); 6 | for (int i = 0;i < n;i++) 7 | for (int j = 0;j < n;j++) 8 | if (i != j && G[i][j]) 9 | { 10 | laplacian.a[i][j] = -1; 11 | laplacian.a[i][i]++; 12 | } 13 | printf("%d\n",laplacian.det(n-1)); 14 | \end{lstlisting} 15 | -------------------------------------------------------------------------------- /graph/bc.tex: -------------------------------------------------------------------------------- 1 | \subsection{双连通分量} 2 | 标号从$0$起 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | const int MAXN=100000*2; 11 | const int MAXM=200000; 12 | struct edges 13 | { 14 | int to,next; 15 | bool cut,visit; 16 | } edge[MAXM<<1]; 17 | int head[MAXN],low[MAXN],dpt[MAXN],L; 18 | bool visit[MAXN],cut[MAXN]; 19 | void init(int n) 20 | { 21 | L=0; 22 | memset(head,-1,4*n); 23 | memset(visit,0,n); 24 | } 25 | void add_edge(int u,int v) 26 | { 27 | edge[L].cut=edge[L].visit=0; 28 | edge[L].to=v; 29 | edge[L].next=head[u]; 30 | head[u]=L++; 31 | } 32 | int idx; 33 | stack st; 34 | int bcc[MAXM]; 35 | void dfs(int u,int fu,int deg) 36 | { 37 | cut[u]=0; 38 | visit[u]=1; 39 | low[u]=dpt[u]=deg; 40 | int tot=0; 41 | for (int i=head[u]; i!=-1; i=edge[i].next) 42 | { 43 | int v=edge[i].to; 44 | if (edge[i].visit) 45 | continue; 46 | st.push(i/2); 47 | edge[i].visit=edge[i^1].visit=1; 48 | if (visit[v]) 49 | { 50 | low[u]=dpt[v]>low[u]?low[u]:dpt[v]; 51 | continue; 52 | } 53 | dfs(v,u,deg+1); 54 | edge[i].cut=edge[i^1].cut=(low[v]>dpt[u] || edge[i].cut); 55 | if (u!=fu) cut[u]=low[v]>=dpt[u]?1:cut[u]; 56 | if (low[v]>=dpt[u] || u==fu) 57 | { 58 | while (st.top()!=i/2) 59 | { 60 | int x=st.top()*2,y=st.top()*2+1; 61 | bcc[st.top()]=idx; 62 | st.pop(); 63 | } 64 | bcc[i/2]=idx++; 65 | st.pop(); 66 | } 67 | low[u]=low[v]>low[u]?low[u]:low[v]; 68 | tot++; 69 | } 70 | if (u==fu && tot>1) cut[u]=1; 71 | } 72 | int main() 73 | { 74 | int n,m; 75 | while (scanf("%d%d",&n,&m)!=EOF) 76 | { 77 | init(n); 78 | for (int i=0; i 4 | #include 5 | #include 6 | struct 7 | { 8 | int x,y; 9 | double z; 10 | } node[1100]; 11 | struct 12 | { 13 | double l,c; 14 | } map[1100][1100]; 15 | int n,l,f[1100],pre[1100]; 16 | double dis[1100]; 17 | double mst(double x) 18 | { 19 | int i,j,tmp; 20 | double min,s=0,t=0; 21 | memset(f,0,sizeof(f)); 22 | f[1]=1; 23 | for (i=2; i<=n; i++) 24 | { 25 | dis[i]=map[1][i].c-map[1][i].l*x; 26 | pre[i]=1; 27 | } 28 | for (i=1; idis[j]) 33 | { 34 | min=dis[j]; 35 | tmp=j; 36 | } 37 | f[tmp]=1; 38 | t+=map[pre[tmp]][tmp].l; 39 | s+=map[pre[tmp]][tmp].c; 40 | for (j=1; j<=n; j++) 41 | if (!f[j] && map[tmp][j].c-map[tmp][j].l*x1e-8) 66 | { 67 | a=b; 68 | b=mst(a); 69 | } 70 | printf("%.3f\n",b); 71 | scanf("%d",&n); 72 | } 73 | } 74 | \end{lstlisting} 75 | -------------------------------------------------------------------------------- /graph/clique.tex: -------------------------------------------------------------------------------- 1 | \subsection{最大团以及相关知识} 2 | \begin{description} 3 | \item[独立集:] 独立集是指图的顶点集的一个子集,该子集的导出子图不含边.如果一个独立集不是任何一个独立集的子集, 那么称这个独立集是一个极大独立集.一个图中包含顶点数目最多的独立集称为最大独立集。最大独立集 一定是极大独立集,但是极大独立集不一定是最大的独立集。 4 | \item[支配集:] 与独立集相对应的就是支配集,支配集也是图顶点集的一个子集,设$S$是图$G$的一个支配集,则对于图中的任意一个顶点$u$,要么属于集合$s$, 要么与$s$中的顶点相邻。在$s$中除去任何元素后$s$不再是支配集,则支配集$s$是极小支配集。称$G$的所有支配集中顶点个数最 少的支配集为最小支配集,最小支配集中的顶点个数成为支配数。 5 | \item[最小点的覆盖:] 最小点的覆盖也是图的顶点集的一个子集,如果我们选中一个点,则称这个点将以他为端点的所有边都覆盖了。将图中所有的边都覆盖所用顶点数最少,这个集合就是最小的点的覆盖。 6 | \item[最大团:] 图$G$的顶点的子集,设$D$是最大团,则$D$中任意两点相邻。若$u$,$v$是最大团,则$u$,$v$有边相连,其补图$u$,$v$没有边相连,所以图$G$的最大团$=$其补图的最大独立集。给定无向图$G=(V,E)$,如果$U$属于$V$,并且对于任意$u$,$v$包含于$U$ 有$$包含于$E$,则称$U$是$G$的完全子图,$G$的完全子图$U$是$G$的团,当且仅当$U$不包含在$G$的更大的完全子图中,$G$的最大团是指$G$中所含顶点数目最多的团。如果$U$属于$V$,并且对于任意$u,v$包含于$U$有$$不包含于$E$,则称$U$是$G$的空子图,$G$的空子图U是G的独立集,当且仅当$U$不包含在$G$的更大的独立集,$G$的最大团是指$G$中所含顶点数目最多的独立集。 7 | \item[一些性质:] 最大独立集$+$最小覆盖集$=V$,最大团$=$补图的最大独立集,最小覆盖集$=$最大匹配 8 | \end{description} 9 | 10 | \begin{lstlisting}[language=c++] 11 | #include 12 | bool am[100][100]; 13 | int ans; 14 | int c[100]; 15 | int U[100][100]; 16 | int n; 17 | bool dfs(int rest,int num) 18 | { 19 | if (!rest) 20 | { 21 | if (num>=ans) 22 | return 1; 23 | else 24 | return 0; 25 | } 26 | int pre=-1; 27 | for (int i=0;i=ans;i++) 28 | { 29 | int idx=U[num][i]; 30 | if (num+c[idx]=0; i--) 50 | { 51 | int rest=0; 52 | for (int j=i+1; j 4 | #include 5 | const int MAXN=10000; 6 | struct edges 7 | { 8 | int to,next; 9 | bool cut,visit; 10 | int from; 11 | } edge[MAXN-1<<1]; 12 | int head[MAXN],low[MAXN],dfn[MAXN],L; 13 | bool visit[MAXN],cut[MAXN]; 14 | void init(int n) 15 | { 16 | L=0; 17 | memset(head,-1,4*n); 18 | memset(cut,0,4*n); 19 | memset(visit,0,4*n); 20 | } 21 | void add_edge(int u,int v) 22 | { 23 | edge[L].from=u; 24 | edge[L].cut=edge[L].visit=0; 25 | edge[L].to=v; 26 | edge[L].next=head[u]; 27 | head[u]=L++; 28 | } 29 | int idx; 30 | void dfs(int u,int fu) 31 | { 32 | visit[u]=1; 33 | low[u]=dfn[u]=idx++; 34 | int tot=0; 35 | for (int i=head[u]; i!=-1; i=edge[i].next) 36 | { 37 | int v=edge[i].to; 38 | if (edge[i].visit) 39 | continue; 40 | edge[i].visit=edge[i^1].visit=1; 41 | if (visit[v]) 42 | { 43 | low[u]=dfn[v]>low[u]?low[u]:dfn[v]; 44 | continue; 45 | } 46 | dfs(v,u); 47 | edge[i].cut=edge[i^1].cut=low[v]>dfn[u] || edge[i].cut; 48 | if (u!=fu) cut[u]=low[v]>=dfn[u]?1:cut[u]; 49 | low[u]=low[v]>low[u]?low[u]:low[v]; 50 | tot++; 51 | } 52 | if (u==fu && tot>1) cut[u]=1; 53 | } 54 | int main() 55 | { 56 | int t; 57 | scanf("%d",&t); 58 | while (t--) 59 | { 60 | int n,m; 61 | scanf("%d%d",&n,&m); 62 | init(n); 63 | for (int i=0; i 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | const int MAXN=100; 11 | const int MAXM=1000; 12 | int N,L; 13 | int head[MAXN]; 14 | struct edges 15 | { 16 | int to,next,cost; 17 | } edge[MAXM]; 18 | int dist[MAXN]; 19 | class states 20 | { 21 | public: 22 | int cost,id; 23 | }; 24 | class cmp 25 | { 26 | public: 27 | bool operator ()(const states &i,const states &j) 28 | { 29 | return i.cost>j.cost; 30 | } 31 | }; 32 | void init(int n) 33 | { 34 | N=n; 35 | L=0; 36 | for (int i=0; i,cmp> q; 54 | q.push(u); 55 | while (!q.empty()) 56 | { 57 | u=q.top(); 58 | q.pop(); 59 | if (u.id==t) return dist[t]; 60 | if (u.cost!=dist[u.id]) continue; 61 | for (int i=head[u.id]; i!=-1; i=edge[i].next) 62 | { 63 | states v=u; 64 | v.id=edge[i].to; 65 | if (dist[v.id]>dist[u.id]+edge[i].cost) 66 | { 67 | v.cost=dist[v.id]=dist[u.id]+edge[i].cost; 68 | q.push(v); 69 | } 70 | } 71 | } 72 | return -1; 73 | } 74 | int main() 75 | { 76 | int n,m; 77 | scanf("%d%d",&n,&m); 78 | init(n); 79 | for (int i=0; i 0) && (Father[Match[v]] > 0))) 95 | BlossomContract(u,v); 96 | else if (Father[v] == 0) 97 | { 98 | Father[v] = u; 99 | if (Match[v] > 0) 100 | Push(Match[v]); 101 | else 102 | { 103 | Finish = v; 104 | return; 105 | } 106 | } 107 | } 108 | } 109 | } 110 | void AugmentPath() 111 | { 112 | int u,v,w; 113 | u = Finish; 114 | while (u > 0) 115 | { 116 | v = Father[u]; 117 | w = Match[v]; 118 | Match[v] = u; 119 | Match[u] = v; 120 | u = w; 121 | } 122 | } 123 | void Edmonds() 124 | { 125 | memset(Match,0,sizeof(Match)); 126 | for (int u = 1; u <= N; u++) 127 | if (Match[u] == 0) 128 | { 129 | Start = u; 130 | FindAugmentingPath(); 131 | if (Finish > 0) AugmentPath(); 132 | } 133 | } 134 | void PrintMatch() 135 | { 136 | for (int u = 1; u <= N; u++) 137 | if (Match[u] > 0) 138 | Count++; 139 | printf("%d\n",Count); 140 | for (int u = 1; u <= N; u++) 141 | if (u < Match[u]) 142 | printf("%d %d\n",u,Match[u]); 143 | } 144 | int main() 145 | { 146 | CreateGraph(); 147 | Edmonds(); 148 | PrintMatch(); 149 | } 150 | \end{lstlisting} -------------------------------------------------------------------------------- /graph/euler.tex: -------------------------------------------------------------------------------- 1 | \subsection{欧拉路} 2 | \subsubsection{有向图} 3 | \begin{lstlisting}[language=c++] 4 | void solve(int x) 5 | { 6 | int i; 7 | if (!match[x]) 8 | { 9 | path[++l]=x; 10 | return ; 11 | } 12 | for (i=1; i<=n; i++) 13 | if (b[x][i]) 14 | { 15 | b[x][i]--; 16 | match[x]--; 17 | solve(i); 18 | } 19 | path[++l]=x; 20 | } 21 | \end{lstlisting} 22 | 23 | \subsubsection{无向图} 24 | \begin{lstlisting}[language=c++] 25 | void solve(int x) 26 | { 27 | int i; 28 | if (!match[x]) 29 | { 30 | path[++l]=x; 31 | return ; 32 | } 33 | for (i=1; i<=n; i++) 34 | if (b[x][i]) 35 | { 36 | b[x][i]--; 37 | b[i][x]--; 38 | match[x]--; 39 | match[i]--; 40 | solve(i); 41 | } 42 | path[++l]=x; 43 | } 44 | \end{lstlisting} 45 | 46 | \subsubsection{混合图} 47 | zju1992 48 | \begin{lstlisting}[language=c++] 49 | int in[MAXN+100],out[MAXN+100]; 50 | int main() 51 | { 52 | int t; 53 | scanf("%d",&t); 54 | while (t--) 55 | { 56 | int n,m; 57 | scanf("%d%d",&n,&m); 58 | N=n+2;L=-1; 59 | for (int i=0;i0) 76 | add_edge(i,n+1,(in[i]-out[i])/2); 77 | else 78 | if (out[i]-in[i]>0) 79 | add_edge(0,i,(out[i]-in[i])/2); 80 | //printf("%d %d %d\n",i,out[i],in[i]); 81 | if ((in[i]+out[i])&1) 82 | { 83 | flag=0; 84 | break; 85 | } 86 | } 87 | maxflow(0,n+1); 88 | for (int i=head[0];i!=-1;i=edge[i].next) 89 | if (edge[i].cap>0 && edge[i].cap>edge[i].flow) 90 | { 91 | flag=0; 92 | break; 93 | } 94 | if (flag) 95 | puts("possible"); 96 | else 97 | puts("impossible"); 98 | } 99 | return 0; 100 | } 101 | \end{lstlisting} -------------------------------------------------------------------------------- /graph/km.tex: -------------------------------------------------------------------------------- 1 | \subsection{KM} 2 | \subsubsection{最大加权匹配} 3 | \begin{lstlisting}[language=c++] 4 | bool visx[N],visy[N];//`x,y中的点是否被访问` 5 | int lx[N],ly[N];//`x,y中的点的标号` 6 | int matchy[N];//`y中各点匹配状态` 7 | int map[N][N];//`二分图描述[x][y]` 8 | bool find(int x) 9 | { 10 | visx[x]=true; 11 | int t; 12 | for (int y=0;yt) lack=t; 27 | } 28 | } 29 | return false; 30 | } 31 | void KM() 32 | { 33 | memset(lx,0,sizeof(lx)); 34 | memset(ly,0,sizeof(ly)); 35 | memset(matchy,-1,sizeof(matchy)); 36 | for (int i=0;ilx[i]) 39 | lx[i]=map[i][j]; 40 | for (int x=0;x 65 | #include 66 | #include 67 | using namespace std; 68 | const int MAXN=100; 69 | const int inf=0x3f3f3f3f; 70 | bool visitx[MAXN],visity[MAXN]; 71 | int labx[MAXN],laby[MAXN],matx[MAXN],maty[MAXN],slack[MAXN]; 72 | int ma[MAXN][MAXN]; 73 | bool check(int x,int n) 74 | { 75 | visitx[x]=1; 76 | for (int i=0; i 4 | #include 5 | #include 6 | using namespace std; 7 | int K; 8 | class states 9 | { 10 | public: 11 | int cost,id; 12 | }; 13 | int dist[1000]; 14 | class cmp 15 | { 16 | public: 17 | bool operator ()(const states &i,const states &j) 18 | { 19 | return i.cost>j.cost; 20 | } 21 | }; 22 | class cmp2 23 | { 24 | public: 25 | bool operator ()(const states &i,const states &j) 26 | { 27 | return i.cost+dist[i.id]>j.cost+dist[j.id]; 28 | } 29 | }; 30 | struct edges 31 | { 32 | int to,next,cost; 33 | } edger[100000],edge[100000]; 34 | int headr[1000],head[1000],Lr,L; 35 | void dijkstra(int s) 36 | { 37 | states u; 38 | u.id=s; 39 | u.cost=0; 40 | dist[s]=0; 41 | priority_queue,cmp> q; 42 | q.push(u); 43 | while (!q.empty()) 44 | { 45 | u=q.top(); 46 | q.pop(); 47 | if (u.cost!=dist[u.id]) continue; 48 | for (int i=headr[u.id]; i!=-1; i=edger[i].next) 49 | { 50 | states v=u; 51 | v.id=edger[i].to; 52 | if (dist[v.id]>dist[u.id]+edger[i].cost) 53 | { 54 | v.cost=dist[v.id]=dist[u.id]+edger[i].cost; 55 | q.push(v); 56 | } 57 | } 58 | } 59 | } 60 | int num[1000]; 61 | void init(int n) 62 | { 63 | Lr=L=0; 64 | memset(head,-1,4*n); 65 | memset(headr,-1,4*n); 66 | memset(dist,63,4*n); 67 | memset(num,0,4*n); 68 | } 69 | void add_edge(int u,int v,int x) 70 | { 71 | edge[L].to=v; 72 | edge[L].cost=x; 73 | edge[L].next=head[u]; 74 | head[u]=L++; 75 | edger[Lr].to=u; 76 | edger[Lr].cost=x; 77 | edger[Lr].next=headr[v]; 78 | headr[v]=Lr++; 79 | } 80 | int a_star(int s,int t) 81 | { 82 | if (dist[s]==0x3f3f3f3f) 83 | return -1; 84 | priority_queue,cmp2> q; 85 | states tmp; 86 | tmp.id=s; 87 | tmp.cost=0; 88 | q.push(tmp); 89 | while (!q.empty()) 90 | { 91 | states u=q.top(); 92 | q.pop(); 93 | num[u.id]++; 94 | if (num[t]==K) 95 | return u.cost; 96 | for (int i=head[u.id]; i!=-1; i=edge[i].next) 97 | { 98 | int v=edge[i].to; 99 | tmp.id=v; 100 | tmp.cost=u.cost+edge[i].cost; 101 | q.push(tmp); 102 | } 103 | } 104 | return -1; 105 | } 106 | int main() 107 | { 108 | int n,m; 109 | scanf("%d%d",&n,&m); 110 | init(n); 111 | for (int i=0; i 5 | #include 6 | #include 7 | using namespace std; 8 | const int NSIZE = 50000; 9 | const int DEG = 20; 10 | struct trees 11 | { 12 | 13 | int fa[DEG]; 14 | int head,deg; 15 | } tree[NSIZE]; 16 | struct edges 17 | { 18 | int to , next; 19 | } edge[NSIZE]; 20 | struct states 21 | { 22 | int u,fu,deg; 23 | }; 24 | int L; 25 | void add_edge(int x, int y) 26 | { 27 | edge[L].to = y; 28 | edge[L].next = tree[x].head; 29 | tree[x].head = L++; 30 | } 31 | int Root; 32 | void BFS(int s) 33 | { 34 | queue que; 35 | states st; 36 | st.deg=0; 37 | st.fu=st.u=s; 38 | que.push(st); 39 | while(!que.empty()) 40 | { 41 | states st=que.front(); 42 | que.pop(); 43 | tree[st.u].deg = st.deg; 44 | tree[st.u].fa[0] = st.fu; 45 | for (int i=1;i tree[y].deg) swap(x,y); 64 | int hx=tree[x].deg,hy=tree[y].deg; 65 | int tx=x,ty=y; 66 | for (int det=hy-hx,i=0; det; det>>=1,i++) 67 | if (det&1) 68 | ty=tree[ty].fa[i]; 69 | if(tx == ty) return tx; 70 | for (int i=DEG-1; i>=0; i--) 71 | { 72 | if(tree[tx].fa[i] == tree[ty].fa[i]) 73 | continue; 74 | tx = tree[tx].fa[i]; 75 | ty = tree[ty].fa[i]; 76 | } 77 | return tree[tx].fa[0]; 78 | } 79 | int main() 80 | { 81 | int t; 82 | scanf("%d",&t); 83 | while(t--) 84 | { 85 | int n; 86 | scanf("%d",&n); 87 | L = 0; 88 | for(int i = 0 ; i < n ; i++) 89 | tree[i].head = -1; 90 | for(int i = 0 ; i < n-1 ; i++) 91 | { 92 | int a,b; 93 | scanf("%d%d",&a ,&b); 94 | add_edge(a-1,b-1); 95 | add_edge(b-1,a-1); 96 | } 97 | Root=0; 98 | BFS(Root); 99 | int a,b; 100 | scanf("%d%d",&a,&b); 101 | int lca=LCA(a-1,b-1)+1; 102 | printf("%d\n",lca); 103 | } 104 | return 0; 105 | } 106 | \end{lstlisting} -------------------------------------------------------------------------------- /graph/marry.tex: -------------------------------------------------------------------------------- 1 | \subsection{稳定婚姻} 2 | 假定有$n$个男生和$m$个女生,理想的拍拖状态就是对于每对情侣$(a,b)$,找不到另一对情侣$(c,d)$使得$c$更喜欢$b$,$b$也更喜欢$c$,同理,对$a$来说也没有$(e,f)$使得$a$更喜欢$e$而$e$更喜欢$a$,当然最后会有一些人落单。这样子一个状态可以称为理想拍拖状态,它也有一个专业的名词叫稳定婚姻。\\ 3 | 求解这个问题可以用一个专有的算法,延迟认可算法,其核心就是让每个男生按自己喜欢的顺序逐个向女生表白,例如leokan向一个女生求爱,这个过程中,若这个女生没有男朋友,那么这个女生就暂时成为leokan的女朋友,或这个女生喜欢她现有男朋友的程度没有喜欢leokan高,这个女生也暂时成为leokan的女朋友,而她原有的男朋友则再将就找下一个次喜欢的女生来当女朋友。 4 | \begin{lstlisting}[language=c++] 5 | #include 6 | #include 7 | #define N 1050 8 | int boy[N][N]; 9 | int girl[N][N]; 10 | int ans[N]; 11 | int cur[N]; 12 | int n; 13 | void getMarry(int g) 14 | { 15 | for (int i=ans[g]+1;i boy[b][g]) 26 | { 27 | cur[b]=g; 28 | ans[g]=i; 29 | getMarry(og); 30 | return; 31 | } 32 | } 33 | }; 34 | int main() 35 | { 36 | int t,a; 37 | scanf("%d",&t); 38 | while(t--) 39 | { 40 | memset(girl,0,sizeof(girl)); 41 | memset(boy,0,sizeof(boy)); 42 | scanf("%d",&n); 43 | for (int i=0;i=3) break; 72 | random_shuffle(P,P+cnt_node); 73 | } 74 | } 75 | int sum=0; 76 | for(i=0; i q; 43 | for (int i=0; iedge[i].flow && 60 | node[v].dis>node[u].dis+edge[i].cost) 61 | { 62 | node[v].dis=node[u].dis+edge[i].cost; 63 | node[v].pre=i; 64 | if (!node[v].visit) 65 | { 66 | node[v].visit=1; 67 | q.push(v); 68 | } 69 | } 70 | } 71 | q.pop(); 72 | } 73 | if (node[t].pre==-1) 74 | return 0; 75 | else 76 | return 1; 77 | } 78 | int mcmf(int s,int t,int &cost) 79 | { 80 | int flow=0; 81 | while (spfa(s,t)) 82 | { 83 | int max=inf; 84 | for (int i=node[t].pre; i!=-1; i=node[edge[i^1].to].pre) 85 | { 86 | if (max>edge[i].cap-edge[i].flow) 87 | max=edge[i].cap-edge[i].flow; 88 | } 89 | for (int i=node[t].pre; i!=-1; i=node[edge[i^1].to].pre) 90 | { 91 | edge[i].flow+=max; 92 | edge[i^1].flow-=max; 93 | cost+=edge[i].cost*max; 94 | } 95 | flow+=max; 96 | } 97 | return flow; 98 | } 99 | \end{lstlisting} -------------------------------------------------------------------------------- /graph/networksimplex.tex: -------------------------------------------------------------------------------- 1 | \subsection{网络单纯形} 2 | 返回pair(流量,费用) 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | const int N = 1100; 11 | const int M = 50000*2*5+2; 12 | struct Node 13 | { 14 | int depth,pot,id; 15 | Node *parent,*thread,*prev,*last; 16 | }; 17 | struct Arc 18 | { 19 | int tail,head,u,c; 20 | }; 21 | Arc arc[M]; 22 | int cnt_arc; 23 | Node nnode[N],*rec[N]; 24 | int cr; 25 | const int inf = 0x22222222; 26 | void dfs(Node *n) 27 | { 28 | cr=0; 29 | rec[cr++]=n; 30 | while(cr) 31 | { 32 | Node *nn=n->thread; 33 | nn->prev=n; 34 | n=nn; 35 | int d=n->depth; 36 | if(d<=rec[cr-1]->depth) 37 | { 38 | Node *l=rec[cr-1]; 39 | while(cr&&d<=rec[cr-1]->depth) 40 | { 41 | rec[--cr]->last=l; 42 | } 43 | } 44 | if(cr) rec[cr++]=n; 45 | } 46 | } 47 | Node*pivot(Node*n1,Node*n2,Node*n3,Node*n4) 48 | { 49 | dfs(n1); 50 | Node *n1l=n1->last,*n3l,*n3p,*end; 51 | if(n1l->thread==n2) 52 | { 53 | n2->parent=n1; 54 | dfs(n3); 55 | return n3->last->thread; 56 | } 57 | if(n1l->thread!=n3) 58 | { 59 | dfs(n4); 60 | n3p=n3->prev; 61 | n3l=n3->last; 62 | n3p->thread=n3l->thread; 63 | if(n3l==n1l) 64 | n3l->thread=n1->thread,n1->thread=n2; 65 | else 66 | n3l->thread=n1l->thread,n1l->thread=n2; 67 | } 68 | else 69 | { 70 | dfs(n3); 71 | n3l=n3->last; 72 | n1l->thread=n2; 73 | } 74 | end=n3l->thread; 75 | Node *n2l=n2->last,*n2lp=NULL,*p2=n1,*pp=NULL; 76 | int pid; 77 | int first=0; 78 | while(n2!=n3) 79 | { 80 | n2l=n2->last; 81 | Node *xp=pp; 82 | if(n2l!=n2lp) xp=n2l,n2lp=n2l; 83 | pp=n2->prev; 84 | pp->thread=xp->thread; 85 | xp->thread=n2->parent; 86 | Node *n2n=n2->parent; 87 | int ppid=n2->id; 88 | if(first) n2->id=pid^1; 89 | pid=ppid; 90 | first++; 91 | n2->parent=p2; 92 | p2=n2; 93 | n2=n2n; 94 | } 95 | if(first) n2->id=pid^1; 96 | n2->parent=p2; 97 | return end; 98 | } 99 | void update(Node *n1,Node *n2) 100 | { 101 | n1=n1->thread; 102 | while(n1!=n2) 103 | { 104 | Node *n1p=n1->parent; 105 | n1->depth=n1p->depth+1; 106 | n1->pot = n1p->pot - arc[n1->id].c; 107 | n1=n1->thread; 108 | } 109 | } 110 | void pivot(int id) 111 | { 112 | int tail=arc[id].tail,head=arc[id].head; 113 | int u=arc[id].u,c=arc[id].c; 114 | Node *uu=nnode+tail,*vv=nnode+head; 115 | Node *mu=0,*mv=0; 116 | int mn_f = u; 117 | while(uu!=vv) 118 | { 119 | int nid; 120 | if(uu->depth>vv->depth) 121 | nid=uu->id,uu=uu->parent; 122 | else nid=vv->id^1,vv=vv->parent; 123 | if(arc[nid].udepth>vv->depth) 132 | { 133 | nid=uu->id; 134 | arc[nid].u-=mn_f; 135 | arc[nid^1].u+=mn_f; 136 | if(arc[nid].u==0&&mu==0) 137 | mu=uu,mv=0; 138 | uu=uu->parent; 139 | } 140 | else 141 | { 142 | nid=vv->id^1; 143 | arc[nid].u-=mn_f; 144 | arc[nid^1].u+=mn_f; 145 | if(arc[nid].u==0&&mu==0) 146 | mv=vv; 147 | vv=vv->parent; 148 | } 149 | } 150 | if(arc[id].u) 151 | { 152 | if(mv) 153 | { 154 | int n3=mv-nnode,n4=mv->parent-nnode; 155 | Node *nx=pivot(nnode+tail,nnode+head,mv,mv->parent); 156 | nnode[head].id=id; 157 | update(nnode+tail,nx); 158 | } 159 | else 160 | { 161 | int n3=mu-nnode,n4=mu->parent-nnode; 162 | Node *nx=pivot(nnode+head,nnode+tail,mu,mu->parent); 163 | nnode[tail].id=id^1; 164 | update(nnode+head,nx); 165 | } 166 | } 167 | } 168 | struct List 169 | { 170 | int v; 171 | List *R; 172 | }; 173 | List lst[M],*cl,*hd; 174 | pair cost(int s,int t,int cnt_node) 175 | { 176 | int tmp_arc=cnt_arc; 177 | int i; 178 | int sid=-1; 179 | nnode[cnt_node].depth=0; 180 | nnode[cnt_node].parent=nnode+cnt_node; 181 | nnode[cnt_node].pot=0; 182 | nnode[cnt_node].thread=nnode; 183 | for(i=0; iR=cl++; 211 | int tail,head,c,cc; 212 | const int MAXQ = cnt_node/4+5; 213 | const int MINQ = cnt_node/10+2; 214 | for(i=0; iv=i; 224 | cl->R=hd->R; 225 | hd->R=cl; 226 | cl++; 227 | tot++; 228 | if(tot>=MAXQ) 229 | { 230 | while(tot>MINQ) 231 | { 232 | List *mj=NULL,*mjp,*it=hd->R,*itp=hd; 233 | int mp=0; 234 | while(it!=hd) 235 | { 236 | int id=it->v; 237 | tail=arc[id].tail,head=arc[id].head,c=arc[id].c; 238 | cc=c-nnode[tail].pot+nnode[head].pot; 239 | if(cc>=0) 240 | { 241 | itp->R=it->R; 242 | tot--; 243 | } 244 | else if(ccR==it) itp=it; 247 | it=it->R; 248 | } 249 | if(mj==NULL) break; 250 | pivot(mj->v); 251 | mjp->R=mj->R; 252 | tot--; 253 | } 254 | } 255 | } 256 | } 257 | while(tot) 258 | { 259 | List *it=hd->R,*itp=hd; 260 | while(it!=hd) 261 | { 262 | int id=it->v; 263 | tail=arc[id].tail,head=arc[id].head; 264 | c=arc[id].c; 265 | cc=c-nnode[tail].pot+nnode[head].pot; 266 | if(cc<0) pivot(id); 267 | itp->R=it->R; 268 | tot--; 269 | it=it->R; 270 | } 271 | } 272 | if(!fd) break; 273 | } 274 | int sum=0; 275 | for(i=0; i(arc[sid].u,sum); 280 | } 281 | void add_arc(int tail,int head,int u,int c) 282 | { 283 | arc[cnt_arc].tail=tail; 284 | arc[cnt_arc].head=head; 285 | arc[cnt_arc].u=u; 286 | arc[cnt_arc].c=c; 287 | cnt_arc++; 288 | } 289 | 290 | void init() 291 | { 292 | cnt_arc = 0; 293 | } 294 | 295 | void add_edge(int x,int y,int cap,int cost) 296 | { 297 | add_arc(x,y,cap,cost); 298 | add_arc(y,x,0,-cost); 299 | } 300 | 301 | int main() 302 | { 303 | int n,m,k; 304 | while (scanf("%d%d%d",&n,&m,&k)!=EOF) 305 | { 306 | init(); 307 | add_edge(0,1,k,0); 308 | for (int i=0;i ret = cost(0,n,n+1); 316 | if (ret.first == k) 317 | printf("%d\n",ret.second); 318 | else 319 | puts("-1"); 320 | } 321 | return 0; 322 | } 323 | \end{lstlisting} 324 | -------------------------------------------------------------------------------- /graph/planar.tex: -------------------------------------------------------------------------------- 1 | \subsection{*二维平面图的最大流} 2 | 待整理\\ 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | const int maxn = 100100; 15 | const int inf = 0x3f3f3f3f; 16 | struct Point 17 | { 18 | int x,y,id; 19 | double theta; 20 | Point() {} 21 | Point(int _x,int _y) 22 | { 23 | x = _x; 24 | y = _y; 25 | } 26 | Point(Point _s,Point _e,int _id) 27 | { 28 | id = _id; 29 | x = _s.x-_e.x; 30 | y = _s.y-_e.y; 31 | theta = atan2(y,x); 32 | } 33 | bool operator < (const Point &b)const 34 | { 35 | return theta < b.theta; 36 | } 37 | }; 38 | 39 | map,int > idmap; 40 | struct Edge 41 | { 42 | int from,to,next,cap,near,mark; 43 | }; 44 | Edge edge[maxn*2]; 45 | int head[maxn],L; 46 | int cntd[maxn]; 47 | void addedge(int u,int v,int cap) 48 | { 49 | cntd[u]++; 50 | cntd[v]++; 51 | idmap[make_pair(u,v)] = L; 52 | edge[L].from = u; 53 | edge[L].to = v; 54 | edge[L].cap = cap; 55 | edge[L].next = head[u]; 56 | edge[L].mark = -1; 57 | head[u] = L++; 58 | } 59 | 60 | int rtp[maxn]; 61 | Point p[maxn],tp[maxn]; 62 | int n,m,S,T; 63 | int vid; 64 | 65 | struct Edge2 66 | { 67 | int to,next,dis; 68 | } edge2[maxn*2]; 69 | int head2[maxn],L2; 70 | 71 | void addedge2(int u,int v,int dis) 72 | { 73 | edge2[L2].to = v; 74 | edge2[L2].dis = dis; 75 | edge2[L2].next = head2[u]; 76 | head2[u] = L2++; 77 | } 78 | 79 | int dist[maxn]; 80 | bool inq[maxn]; 81 | int SPFA(int s,int t) 82 | { 83 | queue Q; 84 | memset(inq,false,sizeof(inq)); 85 | memset(dist,63,sizeof(dist)); 86 | Q.push(s); 87 | dist[s] = 0; 88 | while (!Q.empty()) 89 | { 90 | int now = Q.front(); 91 | Q.pop(); 92 | for (int i = head2[now]; i != -1; i = edge2[i].next) 93 | if (dist[edge2[i].to] > dist[now]+edge2[i].dis) 94 | { 95 | dist[edge2[i].to] = dist[now]+edge2[i].dis; 96 | if (inq[edge2[i].to] == false) 97 | { 98 | inq[edge2[i].to] = true; 99 | Q.push(edge2[i].to); 100 | } 101 | } 102 | inq[now] = false; 103 | } 104 | return dist[t]; 105 | } 106 | 107 | int main() 108 | { 109 | int totcas; 110 | scanf("%d",&totcas); 111 | for (int cas = 1; cas <= totcas; cas++) 112 | { 113 | idmap.clear(); 114 | L = 0; 115 | scanf("%d%d",&n,&m); 116 | S = T = 0; 117 | for (int i = 0; i < n; i++) 118 | { 119 | head[i] = -1; 120 | scanf("%d%d",&p[i].x,&p[i].y); 121 | if (p[S].x > p[i].x) 122 | S = i; 123 | if (p[T].x < p[i].x) 124 | T = i; 125 | cntd[i] = 0; 126 | } 127 | //源汇中间加入一个特殊节点 128 | head[n] = -1; 129 | n ++; 130 | addedge(S,n-1,inf); 131 | addedge(n-1,S,inf); 132 | addedge(T,n-1,inf); 133 | addedge(n-1,T,inf); 134 | 135 | for (int i = 0; i < m; i++) 136 | { 137 | int u,v,cap; 138 | scanf("%d%d%d",&u,&v,&cap); 139 | u--; 140 | v--; 141 | addedge(u,v,cap); 142 | addedge(v,u,cap); 143 | } 144 | 145 | for (int i = 0; i < n; i++) 146 | { 147 | int tot = 0; 148 | //源点汇点连到特殊点的方向需要特别考虑一下 149 | if (i == S) 150 | tp[tot++] = Point(Point(0,0),Point(-1,0),n-1); 151 | else if (i == T) 152 | tp[tot++] = Point(Point(0,0),Point(1,0),n-1); 153 | else if (i == n-1) 154 | { 155 | tp[tot++] = Point(Point(0,0),Point(1,0),S); 156 | tp[tot++] = Point(Point(0,0),Point(-1,0),T); 157 | } 158 | if (i < n-1) 159 | { 160 | for (int j = head[i]; j != -1; j = edge[j].next) 161 | { 162 | if (i == S && edge[j].to == n-1) continue; 163 | if (i == T && edge[j].to == n-1) continue; 164 | tp[tot++] = Point(p[i],p[edge[j].to],edge[j].to); 165 | } 166 | } 167 | sort(tp,tp+tot); 168 | for (int j = 0; j < tot; j++) 169 | rtp[tp[j].id] = j; 170 | for (int j = head[i]; j != -1; j = edge[j].next) 171 | edge[j].near = tp[(rtp[edge[j].to]+1)%tot].id; 172 | } 173 | 174 | vid = 0; 175 | for (int i = 0;i < L;i++) 176 | if (edge[i].mark == -1) 177 | { 178 | int now = edge[i].from; 179 | int eid = i; 180 | int to = edge[i].to; 181 | while (true) 182 | { 183 | edge[eid].mark = vid; 184 | eid ^= 1; 185 | now = to; 186 | to = edge[eid].near; 187 | eid = idmap[make_pair(now,to)]; 188 | 189 | if (now == edge[i].from) break; 190 | } 191 | vid++; 192 | } 193 | 194 | L2 = 0; 195 | for (int i = 0; i < vid; i++) 196 | head2[i] = -1; 197 | for (int i = 0; i < L; i++) 198 | addedge2(edge[i].mark,edge[i^1].mark,edge[i].cap); 199 | printf("%d\n",SPFA(edge[0].mark,edge[1].mark)); 200 | } 201 | return 0; 202 | } 203 | \end{lstlisting} -------------------------------------------------------------------------------- /graph/sap.tex: -------------------------------------------------------------------------------- 1 | \subsection{SAP四版} 2 | \begin{lstlisting}[language=c++] 3 | const int MAXEDGE=20400; 4 | const int MAXN=400; 5 | const int inf=0x3fffffff; 6 | struct edges 7 | { 8 | int cap,to,next,flow; 9 | } edge[MAXEDGE+100]; 10 | struct nodes 11 | { 12 | int head,label,pre,cur; 13 | } node[MAXN+100]; 14 | int L,N; 15 | int gap[MAXN+100]; 16 | void init(int n) 17 | { 18 | L=0; 19 | N=n; 20 | for (int i=0; iedge[i].cap-edge[i].flow) 55 | min=edge[i].cap-edge[i].flow; 56 | for (int i=node[u].pre; i!=-1; i=node[edge[i^1].to].pre) 57 | { 58 | edge[i].flow+=min; 59 | edge[i^1].flow-=min; 60 | } 61 | u=s; 62 | ans+=min; 63 | continue; 64 | } 65 | bool flag=false; 66 | int v; 67 | for (int i=node[u].cur; i!=-1; i=edge[i].next) 68 | { 69 | v=edge[i].to; 70 | if (edge[i].cap-edge[i].flow && 71 | node[v].label+1==node[u].label) 72 | { 73 | flag=true; 74 | node[u].cur=node[v].pre=i; 75 | break; 76 | } 77 | } 78 | if (flag) 79 | { 80 | u=v; 81 | continue; 82 | } 83 | node[u].cur=node[u].head; 84 | int min=N; 85 | for (int i=node[u].head; i!=-1; i=edge[i].next) 86 | if (edge[i].cap-edge[i].flow && node[edge[i].to].label 4 | using namespace std; 5 | const int maxn=510; 6 | int map[maxn][maxn]; 7 | int n; 8 | void contract(int x,int y) 9 | { 10 | int i,j; 11 | for (i=0; ik) 32 | k=w[t=j]; 33 | c[sx=t]=1; 34 | for (j=0; j1) 52 | { 53 | k=mincut(); 54 | if (k n) break; 30 | } 31 | return -1; 32 | } 33 | \end{lstlisting} 34 | 35 | \subsubsection{何老师的版} 36 | \begin{lstlisting}[language=c++] 37 | //离散对数 38 | #include 39 | #include 40 | #include 41 | #include 42 | using namespace std; 43 | typedef long long LL; 44 | struct Hash 45 | { 46 | static const int MOD = 100007; 47 | static const int MaxN = 100005; 48 | struct Node 49 | { 50 | LL k, v;//A^k = v 51 | Node *nxt; 52 | } buf[MaxN], *g[MaxN], *pt; 53 | void init() 54 | { 55 | memset(g,0,sizeof(g)) ; 56 | pt = buf; 57 | } 58 | LL find(LL v) 59 | { 60 | for (Node *now = g[v%MOD]; now; now = now->nxt) 61 | if (now->v == v) 62 | return now->k; 63 | return -1; 64 | } 65 | void Ins(LL k, LL v) 66 | { 67 | if ( find (v) != -1)return; 68 | pt->k = k; 69 | pt->v = v; 70 | pt->nxt = g[v % MOD]; 71 | g[v % MOD] = pt++; 72 | } 73 | }hash; 74 | LL gcd(LL x, LL y) 75 | { 76 | return y==0?x:gcd(y,x%y); 77 | } 78 | LL e_gcd(LL a, LL b, LL &x, LL &y) 79 | { 80 | if (b==0) 81 | { 82 | x = 1; 83 | y = 0; 84 | return a; 85 | } 86 | LL ret = e_gcd(b, a%b, y, x) ; 87 | y = y - a/b*x; 88 | return ret ; 89 | } 90 | LL Baby(LL A, LL B, LL C)//A^x = B (mod C) 91 | { 92 | B %= C; 93 | A %= C; 94 | LL x = 1%C, y; 95 | for (int i = 0; i <= 64; i++) 96 | { 97 | if (x==B)return i; 98 | x = x*A % C; 99 | } 100 | 101 | LL D = 1%C, g; 102 | int cnt = 0; 103 | while((g = gcd(A,C)) != 1) 104 | { 105 | if (B%g) return -1; 106 | cnt++; 107 | C /= g; 108 | B /= g; 109 | D = A/g * D % C; 110 | } 111 | hash. init () ; 112 | int m = (int)sqrt(C); 113 | LL Am = 1%C; 114 | hash.Ins(0,Am); 115 | for (int i = 1; i <= m; i++) 116 | { 117 | Am = Am*A % C; 118 | hash. Ins ( i ,Am); 119 | } 120 | for (int i = 0; i <= m; i++) 121 | { 122 | //D*x = B (mod C), D*x + C*y = B 123 | g = e_gcd(D,C,x,y); 124 | x = (x*B/g%C+C)%C; 125 | LL k = hash.find(x) ; 126 | if (k != -1) return i*m+k+cnt; 127 | D = D*Am % C; 128 | } 129 | return -1; 130 | } 131 | int main() 132 | { 133 | int A,B,C; 134 | while(scanf("%d%d%d",&A,&C,&B) == 3 && (A+B+C)) 135 | { 136 | if (B>=C) 137 | { 138 | puts("Orz,I can’t find D!"); 139 | continue; 140 | } 141 | LL ret = Baby(A,B,C); 142 | if ( ret == -1)puts("Orz,I can’t find D!"); 143 | else printf ("%I64d\n",ret); 144 | } 145 | return 0; 146 | } 147 | \end{lstlisting} -------------------------------------------------------------------------------- /math/MLES.tex: -------------------------------------------------------------------------------- 1 | \subsection{模线性方程组} 2 | \begin{lstlisting}[language=c++] 3 | //有更新 4 | int m[10],a[10];//模数m 余数a 5 | bool solve(int &m0,int &a0,int m,int a)//模线性方程组 6 | { 7 | int y,x; 8 | int g=ex_gcd(m0,m,x,y); 9 | if (abs(a-a0)%g) return 0; 10 | x*=(a-a0)/g; 11 | x%=m/g; 12 | a0=(x*m0+a0); 13 | m0*=m/g; 14 | a0%=m0; 15 | if (a0<0) a0+=m0; 16 | return 1; 17 | } 18 | int MLES() 19 | { 20 | bool flag=1; 21 | int m0=1,a0=0; 22 | for (int i=0; i 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | char s[100000]; 13 | int n,cur; 14 | const string OP = "+-*"; 15 | 16 | char next_char() 17 | { 18 | if (cur >= n) return EOF; 19 | return s[cur]; 20 | } 21 | 22 | int get_priority(char ch) 23 | { 24 | if (ch == '*') return 2; 25 | return 1; 26 | } 27 | 28 | int P(); 29 | 30 | int calc(int a,char op,int b) 31 | { 32 | if (op == '+') 33 | return a+b; 34 | if (op == '-') 35 | return a-b; 36 | if (op == '*') 37 | return a*b; 38 | } 39 | 40 | int calc_exp(int p) 41 | { 42 | int a = P(); 43 | while ((OP.find(next_char()) != OP.npos) && 44 | (get_priority(next_char()) >= p)) 45 | { 46 | char op = next_char(); 47 | cur++; 48 | a = calc(a,op,calc_exp(get_priority(op)+1)); 49 | } 50 | return a; 51 | } 52 | 53 | int totvar,m,var[26],varid[26]; 54 | 55 | int P() 56 | { 57 | if (next_char() == '-') 58 | { 59 | cur++; 60 | return -P(); 61 | } 62 | else if (next_char() == '+') 63 | { 64 | cur++; 65 | return P(); 66 | } 67 | else if (next_char() == '(') 68 | { 69 | cur++; 70 | int res = calc_exp(0); 71 | cur++; 72 | return res; 73 | } 74 | else 75 | { 76 | cur++; 77 | return var[varid[s[cur-1]-'a']]; 78 | } 79 | } 80 | 81 | int id[26],minid; 82 | 83 | int main() 84 | { 85 | while (true) 86 | { 87 | scanf("%d%d",&totvar,&var[0]); 88 | if (totvar == 0 && var[0] == 0) break; 89 | for (int i = 1;i < totvar;i++) 90 | scanf("%d",&var[i]); 91 | scanf("%d",&m); 92 | scanf("%s",s); 93 | for (int i = 0;i < 26;i++) 94 | id[i] = -1; 95 | minid = 0; 96 | n = strlen(s); 97 | for (int i = 0;i < n;i++) 98 | if (s[i] >= 'a' && s[i] <= 'z') 99 | { 100 | if (id[s[i]-'a'] == -1) 101 | { 102 | id[s[i]-'a'] = minid; 103 | minid++; 104 | } 105 | s[i] = 'a'+id[s[i]-'a']; 106 | } 107 | for (int i = 0;i < totvar;i++) 108 | varid[i] = i; 109 | int res = 0; 110 | do 111 | { 112 | cur = 0; 113 | int tmp = calc_exp(0); 114 | if (tmp == m) 115 | { 116 | res++; 117 | break; 118 | } 119 | } 120 | while (next_permutation(varid,varid+totvar)); 121 | //puts(s); 122 | if (res > 0) 123 | puts("YES"); 124 | else 125 | puts("NO"); 126 | } 127 | return 0; 128 | } 129 | \end{lstlisting} 130 | -------------------------------------------------------------------------------- /math/cantor.tex: -------------------------------------------------------------------------------- 1 | \subsection{康拓展开} 2 | \begin{lstlisting}[language=c++] 3 | const int PermSize = 12; 4 | int factory[PermSize] = 5 | {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800}; 6 | int Cantor(int a[]) 7 | { 8 | int i, j, counted; 9 | int result = 0; 10 | for (i = 0; i < PermSize; ++i) 11 | { 12 | counted = 0; 13 | for (j = i + 1; j < PermSize; ++j) 14 | if (a[i] > a[j]) 15 | ++counted; 16 | result = result + counted * factory[PermSize - i - 1]; 17 | } 18 | return result; 19 | } 20 | 21 | bool h[13]; 22 | 23 | void UnCantor(int x, int res[]) 24 | { 25 | int i,j,l,t; 26 | for (i = 1;i <= 12;i++) 27 | h[i] = false; 28 | for (i = 1; i <= 12; i++) 29 | { 30 | t = x / factory[12 - i]; 31 | x -= t * factory[12 - i]; 32 | for (j = 1, l = 0; l <= t; j++) 33 | if (!h[j])l++; 34 | j--; 35 | h[j] = true; 36 | res[i - 1] = j; 37 | } 38 | } 39 | \end{lstlisting} -------------------------------------------------------------------------------- /math/combination.tex: -------------------------------------------------------------------------------- 1 | \subsection{组合数求模} 2 | 模是质数 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | int mod; 9 | long long num[100000]; 10 | int ni[100],mi[100]; 11 | int len; 12 | void init(int p) 13 | { 14 | mod=p; 15 | num[0]=1; 16 | for (int i=1; i>=1,a=a*a%mod) 35 | if (y&1) 36 | ret=ret*a%mod; 37 | return ret; 38 | } 39 | long long getInv(long long x)//`mod为素数` 40 | { 41 | return power(x,mod-2); 42 | } 43 | long long calc(int n,int m,int p)//C(n,m)%p 44 | { 45 | init(p); 46 | long long ans=1; 47 | for (; n && m && ans; n/=p,m/=p) 48 | { 49 | if (n%p>=m%p) 50 | ans = ans*num[n%p]%p*getInv(num[m%p]%p)%p 51 | *getInv(num[n%p-m%p])%p; 52 | else 53 | ans=0; 54 | } 55 | return ans; 56 | } 57 | int main() 58 | { 59 | int t; 60 | scanf("%d",&t); 61 | while (t--) 62 | { 63 | int n,m,p; 64 | scanf("%d%d%d",&n,&m,&p); 65 | printf("%I64d\n",calc(n+m,m,p)); 66 | } 67 | return 0; 68 | } 69 | \end{lstlisting} 70 | -------------------------------------------------------------------------------- /math/euler.tex: -------------------------------------------------------------------------------- 1 | \subsection{欧拉函数} 2 | \subsubsection{分解质因数} 3 | \begin{lstlisting}[language=c++] 4 | int getEuler(int x) 5 | { 6 | getFactor(x); 7 | int ret=x; 8 | for (int i=0; i 5 | #include 6 | #include 7 | int p,expp,A,B,aa,ans,tt; 8 | long long M; 9 | long long exp(int a,int b,long long mod) 10 | { 11 | long long ans=1,num=a; 12 | while (b!=0) 13 | { 14 | if (b&1) 15 | { 16 | ans=((ans%mod)*(num%mod))%mod; 17 | } 18 | num=((num%mod)*(num%mod))%mod; 19 | b>>=1; 20 | } 21 | return ans; 22 | } 23 | int calcu(int p,int &x,int &y) 24 | { 25 | if (p%4!=1) return -1; 26 | else 27 | { 28 | expp=(p-1)/4; 29 | A,B; 30 | while (1) 31 | { 32 | aa=rand()%p; 33 | if (aa==0) continue; 34 | A=exp(aa,expp,p); 35 | ans=(((long long)A%p)*((long long)A%p))%p; 36 | if (ans==p-1) break; 37 | } 38 | B=1; 39 | M=((long long)A*(long long)A+(long long)B*(long long)B)/p; 40 | if (M!=1) B=p; 41 | while (M!=1) 42 | { 43 | if (B>A) 44 | {tt=A; A=B; B=tt;} 45 | tt=A; 46 | A=B; 47 | B=tt%B; 48 | M=((long long)A*(long long)A 49 | +(long long)B*(long long)B)/p; 50 | } 51 | if (B<=A) 52 | { 53 | x=B; 54 | y=A; 55 | } 56 | else 57 | { 58 | x=A; 59 | y=B; 60 | } 61 | } 62 | } 63 | int main() 64 | { 65 | while (scanf("%d",&p)!=EOF) 66 | { 67 | int x,y; 68 | if (calcu(p,x,y)!=-1) 69 | } 70 | return 0; 71 | } 72 | \end{lstlisting} -------------------------------------------------------------------------------- /math/fft.tex: -------------------------------------------------------------------------------- 1 | \subsection{FFT} 2 | \begin{lstlisting}[language=c++] 3 | const double PI= acos(-1.0); 4 | struct vir 5 | { 6 | double re,im; //实部和虚部 7 | vir(double a=0,double b=0) 8 | { 9 | re=a; 10 | im=b; 11 | } 12 | vir operator +(const vir &b) 13 | {return vir(re+b.re,im+b.im);} 14 | vir operator -(const vir &b) 15 | {return vir(re-b.re, im-b.im);} 16 | vir operator *(const vir &b) 17 | {return vir(re*b.re-im*b.im , re*b.im+im*b.re);} 18 | }; 19 | vir x1[200005],x2[200005]; 20 | void change(vir *x,int len,int loglen) 21 | { 22 | int i,j,k,t; 23 | for(i=0;i>=1) 27 | k= (k<<1)|(t&1); 28 | if(k>=1; 68 | s=0; 69 | e=s+t; 70 | while(s=0;i--) 127 | { 128 | t=(int)(x1[i].re+over+0.5); 129 | a[len++]= t%10; 130 | over = t/10; 131 | } 132 | while(over) 133 | { 134 | a[len++]=over%10; 135 | over/=10; 136 | } 137 | for(len--;len>=0&&!a[len];len--); 138 | if(len<0) 139 | putchar('0'); 140 | else 141 | for(;len>=0;len--) 142 | putchar(a[len]+'0'); 143 | putchar('\n'); 144 | } 145 | return 0; 146 | } 147 | \end{lstlisting} 148 | -------------------------------------------------------------------------------- /math/getfactor.tex: -------------------------------------------------------------------------------- 1 | \subsection{分解质因数} 2 | \subsubsection{米勒拉宾+分解因数} 3 | \begin{lstlisting}[language=c++] 4 | #include 5 | #include 6 | #define bint long long 7 | using namespace std; 8 | const int TIME = 8;//测试次数,8~10够了 9 | int factor[100],fac_top = -1; 10 | 11 | //计算两个数的gcd 12 | bint gcd(bint small,bint big) 13 | { 14 | while(small) 15 | { 16 | swap(small,big); 17 | small%=big; 18 | } 19 | return abs(big); 20 | } 21 | 22 | //ret = (a*b)%n (n<2^62) 23 | bint muti_mod(bint a,bint b,bint n) 24 | { 25 | bint exp = a%n, res = 0; 26 | while(b) 27 | { 28 | if(b&1) 29 | { 30 | res += exp; 31 | if(res>n) res -= n; 32 | } 33 | exp <<= 1; 34 | if (exp>n) exp -= n; 35 | b>>=1; 36 | } 37 | return res; 38 | } 39 | 40 | // ret = (a^b)%n 41 | bint mod_exp(bint a,bint p,bint m) 42 | { 43 | bint exp=a%m, res=1; // 44 | while(p>1) 45 | { 46 | if(p&1) 47 | res=muti_mod(res,exp,m); 48 | exp = muti_mod(exp,exp,m); 49 | p>>=1; 50 | } 51 | return muti_mod(res,exp,m); 52 | } 53 | 54 | //miller-rabin法测试素数, time 测试次数 55 | bool miller_rabin(bint n, int times) 56 | { 57 | if(n==2)return 1; 58 | if(n<2||!(n&1))return 0; 59 | bint a, u=n-1, x, y; 60 | int t=0; 61 | while(u%2==0) 62 | { 63 | t++; 64 | u/=2; 65 | } 66 | srand(time(0)); 67 | for(int i=0; i= n) 114 | p = pollard_rho(p,k--);//k值变化,防止死循环 115 | findFactor(p,k); 116 | findFactor(n/p,k); 117 | } 118 | 119 | int main() 120 | { 121 | bint cs,n,min; 122 | cin>>cs; 123 | while (cs--) 124 | { 125 | cin>>n; 126 | fac_top = min = -1; 127 | if(miller_rabin(n,TIME)) cout<<"Prime"<1) 164 | { 165 | num[N]=1; 166 | fac[N++]=x; 167 | } 168 | } 169 | \end{lstlisting} -------------------------------------------------------------------------------- /math/guess.tex: -------------------------------------------------------------------------------- 1 | \subsection{高斯消元} 2 | \begin{lstlisting}[language=c++] 3 | const double eps = 1e-8; 4 | 5 | void Guess(int n) 6 | { 7 | for (int i = 0; i < n; i++) 8 | { 9 | for (int j = i; j < n; j++) 10 | if (fabs(a[j][i]) > eps) 11 | { 12 | for (int k = i; k <= n; k++) 13 | swap(a[i][k],a[j][k]); 14 | break; 15 | } 16 | 17 | if (fabs(a[i][i]) < eps) continue; 18 | 19 | for (int j = 0; j < n; j++) 20 | if (i != j && fabs(a[j][i]) > eps) 21 | { 22 | double det = a[j][i]/a[i][i]; 23 | for (int k = i; k <= n; k++) 24 | a[j][k] -= a[i][k]*det; 25 | } 26 | } 27 | 28 | for (int i = 0; i < n; i++) 29 | { 30 | if (fabs(a[i][i]) < eps) 31 | { 32 | if (fabs(a[i][n]) > eps) 33 | { 34 | //无解 35 | puts("Fuck"); 36 | } 37 | //`否则$x_i$可以是任意解` 38 | } 39 | else 40 | { 41 | a[i][n] /= a[i][i]; 42 | if (fabs(a[i][n]) < eps) 43 | a[i][n] = 0; 44 | } 45 | } 46 | 47 | } 48 | \end{lstlisting} 49 | -------------------------------------------------------------------------------- /math/inv.tex: -------------------------------------------------------------------------------- 1 | \subsection{逆元} 2 | \begin{lstlisting}[language=c++] 3 | void getInv2(int x) 4 | { 5 | inv[1]=1; 6 | for (int i=2; i<=x; i++) 7 | inv[i]=(mod-(mod/i)*inv[mod%i]%mod)%mod; 8 | } 9 | int getInv(int x)//mod为素数 10 | { 11 | return power(x,mod-2); 12 | } 13 | \end{lstlisting} -------------------------------------------------------------------------------- /math/lucus.tex: -------------------------------------------------------------------------------- 1 | \subsection{卢卡斯} 2 | 卢卡斯,$num[i]$阶乘也 3 | \begin{lstlisting}[language=c++] 4 | int comLucus(int n,int m,int p) 5 | { 6 | int ans=1; 7 | for (; n && m && ans; n/=p,m/=p) 8 | { 9 | if (n%p>=m%p) 10 | ans = ans*num[n%p]%p*getInv(num[m%p]%p)%p 11 | *getInv(num[n%p-m%p])%p; 12 | else 13 | ans=0; 14 | } 15 | return ans; 16 | } 17 | \end{lstlisting} 18 | -------------------------------------------------------------------------------- /math/matrix.tex: -------------------------------------------------------------------------------- 1 | \subsection{矩阵} 2 | 乘法的时候将$B$数组转置一下然后$C[i][j] = \sum{A[i][k]\times B[j][k]}$会有奇效。 3 | \begin{lstlisting}[language=c++] 4 | struct Matrix 5 | { 6 | int a[52][52]; 7 | void clear() 8 | { 9 | memset(a,0,sizeof(a)); 10 | } 11 | int det(int n)//求行列式的值模上一个数,需要预处理逆元 12 | { 13 | for (int i = 0;i < n;i++) 14 | for (int j = 0;j < n;j++) 15 | a[i][j] = (a[i][j]%mod+mod)%mod; 16 | int res = 1; 17 | for (int i = 0;i < n;i++) 18 | { 19 | for (int j = i;j < n;j++) 20 | if (a[j][i] != 0) 21 | { 22 | for (int k = i;k < n;k++) 23 | swap(a[i][k],a[j][k]); 24 | if (i != j) 25 | res = (res+mod)%mod; 26 | break; 27 | } 28 | if (a[i][i] == 0) 29 | { 30 | res = -1;//不存在 31 | break; 32 | } 33 | for (int j = i+1;j < n;j++) 34 | { 35 | int mut = (a[j][i]*inv[a[i][i]])%mod; 36 | for (int k = i;k < n;k++) 37 | a[j][k] = (a[j][k]-(a[i][k]*mut)%mod+mod)%mod; 38 | } 39 | res = (res*a[i][i])%mod; 40 | } 41 | return res; 42 | } 43 | Matrix operator * (const Matrix &b)const 44 | { 45 | Matrix res; 46 | for (int i = 0; i < 52; i++) 47 | for (int j = 0; j < 52; j++) 48 | { 49 | res.a[i][j] = 0; 50 | for (int k = 0; k < 52; k++) 51 | res.a[i][j] += a[i][k] * b.a[k][j]; 52 | } 53 | return res; 54 | } 55 | Matrix operator ^ (int y)const 56 | { 57 | Matrix res, x; 58 | for (int i = 0; i < 52; i++) 59 | { 60 | for (int j = 0; j < 52; j++) 61 | res.a[i][j] = 0, x.a[i][j] = a[i][j]; 62 | res.a[i][i] = 1; 63 | } 64 | for (; y; y >>= 1, x = x * x) 65 | if (y & 1) 66 | res = res * x; 67 | return res; 68 | } 69 | }; 70 | \end{lstlisting} 71 | -------------------------------------------------------------------------------- /math/others.tex: -------------------------------------------------------------------------------- 1 | \subsection{其它公式} 2 | \subsubsection{Polya} 3 | 设$G$是$p$个对象的一个置换群,用$k$种颜色去染这$p$个对象,若一种染色方案在群$G$的作用下变为另一种方案,则这两个方案当作是同一种方案,这样的不同染色方案数为:\\ 4 | $L=\frac{1}{\left |G \right |}\times \Sigma(k^{C(f)}), f\in G$\\ 5 | $C(f)$为循环节,$\left |G \right |$表示群的置换方法数\\ 6 | \\ 7 | 对于有$n$个位置的手镯,有$n$种旋转置换和$n$种翻转置换 8 | \begin{description} 9 | \item[对于旋转置换:] ~\\ 10 | $C(f_i)=gcd(n,i)$ ,$i$表示一次转过i颗宝石,$i=0$时$c=n$;\\ 11 | \item[对于翻转置换:] ~\\ 12 | \begin{description} 13 | \item[如果$n$为偶数:] 则有$\frac{n}{2}$个置换$C(f)=\frac{n}{2}$,有$\frac{n}{2}$个置换 $C(f)=\frac{n}{2}+1$\\ 14 | \item[如果$n$为奇数:] $C(f)=\frac{n}{2}+1$\\ 15 | \end{description} 16 | \end{description} 17 | 18 | \subsubsection{拉格朗日插值法} 19 | 已知$y=a_0+a_1x+a_2x^2+\cdots +a_{n-1}x^{n-1}$曲线上的$n$个点$(x_1,y_1),(x_2,y_2),(x_3,y_3)\cdots (x_n,y_n)$\\ 20 | 用拉格朗日插值法可以不求系数可知任意$x$对应的$y$值。\\ 21 | \[ \begin{split} 22 | y &= y_1\frac{(x-x_2)(x-x_3)\cdots (x-x_n)}{(x_1-x_2)(x_1-x_3)\cdots (x_1-x_n)}\\ 23 | &+ y_2\frac{(x-x_1)(x-x_3)\cdots (x-x_n)}{(x_2-x_1)(x_2-x_3)\cdots (x_2-x_n)}\\ 24 | &+ \cdots \\ 25 | &+ y_n\frac{(x-x_1)(x-x_2)\cdots (x-x_{n-1})}{(x_n-x_1)(x_n-x_2)\cdots (x_n-x_{n-1})}\\ 26 | \end{split}\] 27 | 特别的,如果$x_1\sim x_n$为 连续自然数,那么对于下一个自然数对应的$y$值为:\\ 28 | \[y_{n+1}=(-1)^{n-1}C_n^0y_1+(-1)^{n-2}C_n^1y_2+\cdots +(-1)^0C_n^{n-1}y_n\] 29 | 这个组合系数可以通过高斯消元暴出来,前提是要猜到它满足递推关系。\\ 30 | 31 | \subsubsection{正多面体顶点着色} 32 | 正四面体:$N = \frac{(n^{4}+11\times n^{2})}{12}$\\ 33 | 正六面体:$N = \frac{(n^{8}+17\times n^{4}+6\times n^{2})}{24}$\\ 34 | 正八面体:$N = \frac{(n^{6}+3\times n^{4}+12\times n^{3}+8\times n^{2})}{24}$\\ 35 | 正十二面体:$N = \frac{(n^{20}+15\times n^{10}+20\times n^{8}+24\times n^{4})}{60}$\\ 36 | 正二十面体:$N = \frac{(n^{12}+15\times n^{6}+44\times n^{4})}{60}$\\ 37 | 38 | \subsubsection{求和公式} 39 | $\sum{k} = \frac{n\times (n+1)}{2}$\\ 40 | $\sum{2k-1} = n^{2}$\\ 41 | $\sum{k^{2}} = \frac{n\times (n+1)\times (2n+1)}{6}$\\ 42 | $\sum{(2k-1)^{2}} = \frac{n\times (4n^{2}-1)}{3}$\\ 43 | $\sum{k^{3}} = (\frac{n\times (n+1)}{2})^{2}$\\ 44 | $\sum{(2k-1)^{3}} = n^{2}\times (2n^{2}-1)$\\ 45 | $\sum{k^{4}} = \frac{n\times (n+1)\times (2n+1)\times (3n^{2}+3n-1)}{30}$\\ 46 | $\sum{k^{5}} = \frac{n^{2}\times (n+1)^{2}\times (2n^{2}+2n-1)}{12}$\\ 47 | $\sum{k\times (k+1)} = \frac{n\times (n+1)\times (n+2)}{3}$\\ 48 | $\sum{k\times (k+1)\times (k+2)} = \frac{n\times (n+1)\times (n+2)\times (n+3)}{4}$\\ 49 | $\sum{k\times (k+1)\times (k+2)\times (k+3)} = \frac{n\times (n+1)\times (n+2)\times (n+3)\times (n+4)}{5}$\\ 50 | 51 | \subsubsection{几何公式} 52 | 球扇形:\\ 53 | 全面积:$T = \pi r(2h+r_0)$,$h$为球冠高,$r_0$为球冠底面半径\\ 54 | 体积:$V = \frac{2\pi r^{2}h}{3}$\\ 55 | 56 | \subsubsection{小公式} 57 | Pick 公式:$A = E\times 0.5+I-1$($A$是多边形面积,$E$是边界上的整点,$I$是多边形内部的整点)\\ 58 | \\ 59 | 海伦公式:$S = \sqrt{p(p-a)(p-b)(p-c)}$,其中$p = \frac{(a+b+c)}{2}$,$abc$为三角形的三条边长\\ 60 | \\ 61 | 求$\binom{n}{k}$中素因子$P$的个数:\\ 62 | \begin {enumerate} 63 | \item 把$n$转化为$P$进制,并记它每个位上的和为$S1$ 64 | \item 把$n-k$,$k$做同样的处理,得到$S2$,$S3$ 65 | \end{enumerate} 66 | 则$\binom{n}{k}$中素因子$P$的个数:$\frac{S2+S3-S1}{P-1}$\\ 67 | \\ 68 | 部分错排公式:\\ 69 | $n+m$个数中$m$个数必须错排 求排列数 70 | \begin{lstlisting}[language=c++] 71 | dp[i] = n*dp[i-1]+(i-1)*(dp[i-1]+dp[i-2]); 72 | dp[0] = n!; 73 | dp[1] = n*n!; 74 | \end{lstlisting} 75 | $dp[m]$为所求解\\ 76 | 77 | \subsubsection{马步问题} 78 | 任意步长$(p,q)$无限棋盘可达性判定 79 | \begin{lstlisting}[language=c++] 80 | bool check(int dx,int dy,int p,int q) 81 | { 82 | if (p < 0) p = -p; 83 | if (q < 0) q = -q; 84 | LL g = gcd(p,q); 85 | if (dx % g || dy % g) return false; 86 | dx /= g,dy /= g,p = (p / g) & 1,q = (q / g) & 1; 87 | return !(p == q && ((dx ^ dy) & 1)); 88 | } 89 | \end{lstlisting} 90 | 拓展:\\ 91 | 若可选马步可以有$N$种$(p_i,q_i)$,令$g = gcd(p_1,q_1,p_2,q_2\cdots p_N,q_N)$,则不在$g$的整数倍点上的节点肯定不可达。坐标除$2g$,同时将可选马步除$g$之后放缩到$2\times 2$之内,即$(\frac{p_i}{g}\mod 2,\frac{q_i}{g}\mod 2)$。若放缩后马步中有$(1,0)$或$(0,1)$,则全放缩后全棋盘可达,否则只可达偶点。\\ 92 | \\ 93 | (2,1)马步无限棋盘最小距离 94 | \begin{lstlisting}[language=c++] 95 | int dis(int dx,int dy) 96 | { 97 | if (dx < 0) dx = -dx; 98 | if (dy < 0) dy = -dy; 99 | if (dx < dy) swap(dx,dy); 100 | if (dx & 1) 101 | { 102 | if (dy & 1) return dis(dx+1,dy-1); 103 | if (dx == 1 && dy == 0) return 3; 104 | return dis(dx+3,dy)-1; 105 | } 106 | if (dy & 1) 107 | { 108 | if (dx == 4 && dy == 3) return 3; 109 | return dis(dx-2,dy-1)+1; 110 | } 111 | if (dx == 0 && dy == 0) return 0; 112 | if (dx == 2 && dy == 2) return 4; 113 | int c = (((dx-1) / 4)+1)*2; 114 | if (dx & 2) dy -= 2; 115 | if (dy <= c) return c; 116 | dy -= c; 117 | return c+(dy-2) / 6*2+2; 118 | } 119 | \end{lstlisting} -------------------------------------------------------------------------------- /math/partition.tex: -------------------------------------------------------------------------------- 1 | \subsection{整数拆分} 2 | \begin{lstlisting}[language=c++] 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | bool check(int x) 10 | { 11 | for (int i=2; i*i<=x; i++) 12 | if (x%i==0) 13 | return 0; 14 | return 1; 15 | } 16 | int p[100000]; 17 | inline int calc(int x) 18 | { 19 | return x*(x*3-1)/2; 20 | } 21 | int main() 22 | { 23 | p[0]=1; 24 | for (int i=1;i<100000;i++) 25 | { 26 | for (int j=1,k=1;calc(j)<=i;j++,k*=-1) 27 | { 28 | p[i]+=k*p[i-calc(j)]; 29 | if (p[i]<0) 30 | p[i]+=1000000; 31 | if (p[i]>=1000000) 32 | p[i]-=1000000; 33 | if (calc(-j)<=i) 34 | p[i]+=k*p[i-calc(-j)]; 35 | if (p[i]<0) 36 | p[i]+=1000000; 37 | if (p[i]>=1000000) 38 | p[i]-=1000000; 39 | } 40 | if (!p[i]) 41 | printf("%d\n",i); 42 | } 43 | return 0; 44 | } 45 | \end{lstlisting} 46 | -------------------------------------------------------------------------------- /math/prime.tex: -------------------------------------------------------------------------------- 1 | \subsection{线性筛} 2 | \begin{lstlisting}[language=c++] 3 | int N; 4 | bool isPrime[10001]; 5 | int prime[10000]; 6 | void getPrime(int n) 7 | { 8 | memset(isPrime,1,++n); 9 | N=0; 10 | isPrime[0]=isPrime[1]=0; 11 | for (int i=2;ib) return 1; 17 | return -1; 18 | } 19 | 20 | void Pivot(int l,int e) 21 | { 22 | double t=A[l][e],p=c[e]; 23 | b[l]=b[l]/t; 24 | for(int i=1;i<=C;i++) 25 | A[l][i]/=t; 26 | V=V-c[e]*b[l]; 27 | for(int i=1;i<=R;i++) 28 | { 29 | if(i==l||fcmp(A[i][e],0.0)==0) 30 | continue; 31 | t=A[i][e]; 32 | b[i]=b[i]-t*b[l]; 33 | for(int j=1;j<=C;j++) 34 | A[i][j]=A[i][j]-t*A[l][j]; 35 | } 36 | for(int i=1;i<=C;i++) 37 | c[i]=c[i]-p*A[l][i]; 38 | for(int i=1;i<=nCnt;i++) 39 | { 40 | if(N[i]==e) 41 | { 42 | N[i]=B[l]; 43 | break; 44 | } 45 | } 46 | B[l]=e; 47 | } 48 | 49 | bool Process(double P[]) 50 | { 51 | while(true) 52 | { 53 | int e=-1; 54 | double mV=-INF; 55 | for(int i=1;i<=nCnt;i++) 56 | if(fcmp(P[N[i]],mV)==1) 57 | mV=P[N[i]],e=N[i]; 58 | 59 | if(fcmp(mV,0.0)<=0) break; 60 | int l=-1; 61 | mV=INF; 62 | for(int i=1;i<=bCnt;i++) 63 | { 64 | if(fcmp(A[i][e],0.0)==1) 65 | { 66 | double t=b[i]/A[i][e]; 67 | if(fcmp(mV,t)==1||(fcmp(mV,t)==0&&(l==-1||B[l]>B[i]))) 68 | mV=t,l=i; 69 | } 70 | } 71 | if(l==-1) return false; 72 | Pivot(l,e); 73 | } 74 | return true; 75 | } 76 | 77 | bool initSimplex() 78 | { 79 | nCnt=bCnt=0; 80 | for(int i=1;i<=n;i++) 81 | N[++nCnt]=i; 82 | for(int i=1;i<=m;i++) 83 | B[++bCnt]=i+n,A[i][n+i]=1.0; 84 | R=bCnt,C=bCnt+nCnt; 85 | double minV=INF; 86 | int p=-1; 87 | for(int i=1;i<=m;i++) 88 | if(fcmp(minV,b[i])==1) 89 | minV=b[i],p=i; 90 | if(fcmp(minV,0.0)>=0) 91 | return true; 92 | N[++nCnt]=n+m+1;R++,C++; 93 | for(int i=0;i<=C;i++) 94 | A[R][i]=0.0; 95 | for(int i=1;i<=R;i++) 96 | A[i][n+m+1]=-1.0; 97 | Pivot(p,n+m+1); 98 | if(!Process(A[R])) return false; 99 | if(fcmp(b[R],0.0)!=0) 100 | return false; 101 | p=-1; 102 | for(int i=1;i<=bCnt&&p==-1;i++) 103 | if(B[i]==n+m+1) p=i; 104 | if(p!=-1) 105 | { 106 | for(int i=1;i<=nCnt;i++) 107 | { 108 | if(fcmp(A[p][N[i]],0.0)!=0) 109 | { 110 | Pivot(p,N[i]); 111 | break; 112 | } 113 | } 114 | } 115 | bool f=false; 116 | for(int i=1;i<=nCnt;i++) 117 | { 118 | if(N[i]==n+m+1) f=true; 119 | if(f&&i+1<=nCnt) 120 | N[i]=N[i+1]; 121 | } 122 | nCnt--; 123 | R--,C--; 124 | return true; 125 | } 126 | 127 | //-1: no solution 1: no bound 0: has a solution -V 128 | int Simplex() 129 | { 130 | if(!initSimplex()) 131 | return -1; 132 | if(!Process(c)) 133 | return 1; 134 | for(int i=1;i<=nCnt;i++) 135 | X[N[i]]=0.0; 136 | for(int i=1;i<=bCnt;i++) 137 | X[B[i]]=b[i]; 138 | return 0; 139 | } 140 | 141 | int main() 142 | { 143 | //n = 1;m=1; 144 | //V= 0.0; 145 | //c[1] = 1.0; 146 | //A[1][1] = 1.0; 147 | //b[1] = 5.0; 148 | //Simplex(); 149 | //printf("V = %.3f\n",V); 150 | 151 | while(scanf("%d",&v1[1]) == 1) 152 | { 153 | for(int i = 2; i<=6;i++) 154 | scanf("%d",&v1[i]); 155 | n = 4; m = 6; 156 | for(int i = 0 ; i<=m+1;i++) 157 | for(int j=0;j<=n+m+2;j++) 158 | A[i][j] = c[j] = 0; 159 | memset(b,0,sizeof(b)); 160 | V = 0.0; 161 | /* 162 | `n 为未知数个数` 163 | `m 为约束个数` 164 | `目标:siama(c[i]*xi)` 165 | `约束:sigma(A[i][j]*xj) <=b[i]; j = 1 ... n` 166 | `解存在X里面` 167 | */ 168 | b[1] = v1[1] ; A[1][1] = 1;A[1][4] = 1; 169 | b[2] = v1[2] ; A[2][1] = 1;A[2][3] = 1; 170 | b[3] = v1[3] ; A[3][3] = 1;A[3][4] = 1; 171 | b[4] = v1[4] ; A[4][2] = 1;A[4][3] = 1; 172 | b[5] = v1[5] ; A[5][2] = 1;A[5][4] = 1; 173 | b[6] = v1[6] ; A[6][1] = 1;A[6][2] = 1; 174 | c[1] = 1;c[2] = 1;c[3] = 1;c[4] = 1; 175 | Simplex(); 176 | //printf("V = %.3f\n",V); 177 | printf("%.3f %.3f %.3f %.3f\n",X[1],X[2],X[3],X[4]); 178 | 179 | } 180 | return 0; 181 | } 182 | \end{lstlisting} 183 | -------------------------------------------------------------------------------- /notice.tex: -------------------------------------------------------------------------------- 1 | \section{注意事项} 2 | \Large 3 | \hrule\ 4 | \\ 5 | 输入输出格式?调试信息?初始化?算术溢出?数组大小?\\ 6 | \\ 7 | 左右端点范围?acos/asin/sqrt 函数定义域?精度问题?\\ 8 | \\ 9 | 二分答案?暴力?单调性?凸性?块状结构?函数式?对偶问题?\\ 10 | \\ 11 | \hrule\ 12 | \\ 13 | 排序的时候注意一下是否需要记录排序前的位置!\\ 14 | \\ 15 | 使用map进行映射的时候,不要用下面这种不安全写法 16 | \begin{lstlisting}[language=c++, 17 | basicstyle=\sf\Large, 18 | numberstyle=\sf\Large, 19 | commentstyle=\sf\Large] 20 | if (mp.find(s) == mp.end()) 21 | mp[s] = mp.size()-1;//挂成狗 22 | 23 | if (mp.find(s) == mp.end()) 24 | { 25 | int tmp = mp.size(); 26 | mp[s] = tmp;//正确 27 | } 28 | \end{lstlisting} 29 | ~\\ 30 | $10^{6}$数量级慎用后缀数组\\ 31 | \\ 32 | TLE的时候要冷静哟。。\\ 33 | \\ 34 | 思考的时候结合具体步骤来的话 会体会到一些不同的东西\\ 35 | \\ 36 | C++与G++是很不一样的。。。\\ 37 | \\ 38 | map套字符串是很慢的。。。\\ 39 | \\ 40 | 栈会被记录内存。。。\\ 41 | \\ 42 | 浮点数最短路要注意取$\leq$来判断更新。。。\\ 43 | \\ 44 | 注意 long long\\ 45 | \\ 46 | 不要相信.size()\\ 47 | \\ 48 | 重复利用数组时 小心数组范围\\ 49 | \\ 50 | 先构思代码框架 每当实际拍马框架变化时 停手 重新思考\\ 51 | \\ 52 | 有时候四边形不等式也是帮得上忙的 dp 优化是可以水的\\ 53 | \\ 54 | 结构体里面带数组会非常慢,有时候 BFS 把数组压成数字会快很多。\\ 55 | \\ 56 | \begin{lstlisting}[language=c++, 57 | basicstyle=\sf\Large, 58 | numberstyle=\sf\Large, 59 | commentstyle=\sf\Large] 60 | void fun(int a[]) 61 | { 62 | printf("%d\n",sizeof(a)); 63 | } 64 | \end{lstlisting} 65 | 结果是 sizeof(a[0]),如果传数组指针然后要清空的话不要用 sizeof。\\ 66 | \\ 67 | sqrt 某些时候会出现 sqrt(-0.00)的问题。\\ 68 | \\ 69 | 将code::blocks的默认终端改成gnome-terminal 70 | \begin{lstlisting}[language=c++, 71 | basicstyle=\sf\Large, 72 | numberstyle=\sf\Large, 73 | commentstyle=\sf\Large] 74 | gnome-terminal -t $TITLE -x 75 | \end{lstlisting} 76 | ~\\ 77 | 最小割割集找法 在残量网络中从源点出发能到的点集记为S原图中S到S’的边即是最小割集\\ 78 | \\ 79 | double全局变量初始值可能不是$0$\\ 80 | \normalsize -------------------------------------------------------------------------------- /others.tex: -------------------------------------------------------------------------------- 1 | \section{杂物} 2 | \input others/bigint.tex 3 | \input others/readint.tex 4 | \input others/java.tex 5 | \input others/hashmap.tex 6 | \input others/stl.tex 7 | \input others/bit.tex 8 | \input others/others.tex -------------------------------------------------------------------------------- /others/bigint.tex: -------------------------------------------------------------------------------- 1 | \subsection{高精度数} 2 | 支持乘以整数和加法。\\ 3 | \begin{lstlisting}[language=c++] 4 | struct BigInt 5 | { 6 | const static int mod = 100000000; 7 | int a[600],len; 8 | BigInt (){} 9 | BigInt (int v) 10 | { 11 | len = 0; 12 | do 13 | { 14 | a[len++] = v%mod; 15 | v /= mod; 16 | }while(v); 17 | } 18 | BigInt operator *(const int& b) const 19 | { 20 | BigInt res; 21 | res.len = len; 22 | for (int i = 0; i <= len; ++i) 23 | res.a[i] = 0; 24 | for (int i = 0; i < len; ++i) 25 | { 26 | res.a[i] += a[i]*b; 27 | res.a[i+1] += res.a[i]/mod; 28 | res.a[i] %= mod; 29 | } 30 | if (res.a[len] > 0) res.len++; 31 | return res; 32 | } 33 | BigInt operator +(const BigInt& b) const 34 | { 35 | BigInt res; 36 | res.len = max(len,b.len); 37 | for (int i = 0; i <= res.len; ++i) 38 | res.a[i] = 0; 39 | for (int i = 0; i < res.len; ++i) 40 | { 41 | res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0); 42 | res.a[i+1] += res.a[i]/mod; 43 | res.a[i] %= mod; 44 | } 45 | if (res.a[res.len] > 0) res.len++; 46 | return res; 47 | } 48 | void output() 49 | { 50 | printf("%d",a[len-1]); 51 | for (int i = len-2; i >= 0; --i) 52 | printf("%08d",a[i]); 53 | printf("\n"); 54 | } 55 | }; 56 | \end{lstlisting} -------------------------------------------------------------------------------- /others/bit.tex: -------------------------------------------------------------------------------- 1 | \subsection{位运算} 2 | \subsubsection{基本操作} 3 | 注意括号\\ 4 | \begin{table}[htbp] 5 | \centering 6 | \begin{tabular}{l|l|l} 7 | \toprule 8 | 功能 & 示例 & 位运算\\ 9 | \midrule 10 | 去掉最后一位 & $(101101\rightarrow 10110)$ & x shr 1\\ 11 | 在最后加一个$0$ & $(101101\rightarrow1011010)$ & x shl 1\\ 12 | 在最后加一个$1$ & $(101101\rightarrow1011011)$ & x shl 1+1\\ 13 | 把最后一位变成$1$ & $(101100\rightarrow101101)$ & x or 1\\ 14 | 把最后一位变成$0$ & $(101101\rightarrow101100)$ & x or 1-1\\ 15 | 最后一位取反 & $(101101\rightarrow101100)$ & x xor 1\\ 16 | 把右数第$k$位变成$1$ & $(101001\rightarrow101101,k=3)$ & x or (1 shl (k-1))\\ 17 | 把右数第$k$位变成$0$ & $(101101\rightarrow101001,k=3)$ & x and not (1 shl (k-1))\\ 18 | 右数第$k$位取反 & $(101001\rightarrow101101,k=3)$ & x xor (1 shl (k-1))\\ 19 | 取末三位 & $(1101101\rightarrow101)$ & x and 7\\ 20 | 取末$k$位 & $(1101101\rightarrow1101,k=5)$ & x and (1 shl k-1)\\ 21 | 取右数第$k$位 & $(1101101\rightarrow1,k=4)$ & x shr (k-1) and 1\\ 22 | 把末$k$位变成$1$ & $(101001\rightarrow101111,k=4)$ & x or (1 shl k-1)\\ 23 | 末$k$位取反 & $(101001\rightarrow100110,k=4)$ & x xor (1 shl k-1)\\ 24 | 把右边连续的$1$变成$0$ & $(100101111\rightarrow100100000)$ & x and (x+1)\\ 25 | 把右起第一个$0$变成$1$ & $(100101111\rightarrow100111111)$ & x or (x+1)\\ 26 | 把右边连续的$0$变成$1$ & $(11011000\rightarrow11011111)$ & x or (x-1)\\ 27 | 取右边连续的$1$ & $(100101111\rightarrow1111)$ & (x xor (x+1)) shr 1\\ 28 | 去掉右起第一个$1$的左边 & $(100101000\rightarrow1000)$ & x and (x xor (x-1))\\ 29 | \bottomrule 30 | \end{tabular} 31 | \end{table} 32 | 33 | \subsubsection{枚举长为$n$含$k$个$1$的$01$串} 34 | \begin{lstlisting}[language=c++] 35 | int n = 5,k = 3; 36 | for (int s = (1 << k)-1,u = 1 << n; s < u;) 37 | { 38 | for (int i = 0;i < n;i++) 39 | printf("%d",(((s>>(n-1-i))&1) == 1)); 40 | printf("\n"); 41 | 42 | int b = s & -s; 43 | s = (s+b)|(((s^(s+b))>>2)/b); 44 | } 45 | \end{lstlisting} 46 | -------------------------------------------------------------------------------- /others/hashmap.tex: -------------------------------------------------------------------------------- 1 | \subsection{hashmap} 2 | \begin{lstlisting}[language=c++] 3 | struct hash_map 4 | { 5 | const static int mod=10007; 6 | int head[mod]; 7 | struct hash_tables 8 | { 9 | int key; 10 | int val; 11 | int next; 12 | } ele[10007]; 13 | int N; 14 | int getHash(int x) 15 | { 16 | return x%mod; //小心负数 17 | } 18 | void init() 19 | { 20 | memset(head,255,sizeof(head)); 21 | N=0; 22 | } 23 | void clear() 24 | { 25 | for (int i = 0; i < N; i++) 26 | head[getHash(ele[i].key)] = -1; 27 | N = 0; 28 | } 29 | int fint(int x) 30 | { 31 | for (int i=head[getHash(x)]; i!=-1; i=ele[i].next) 32 | if (ele[i].key==x) return i; 33 | return -1; 34 | } 35 | void insert(int x) 36 | { 37 | int tmp=getHash(x); 38 | ele[N].key=x; 39 | ele[N].val=0; 40 | ele[N].next=head[tmp]; 41 | head[tmp]=N++; 42 | } 43 | int& operator [](int x) 44 | { 45 | int tmp=fint(x); 46 | if (tmp==-1) 47 | { 48 | insert(x); 49 | return ele[N-1].val; 50 | } 51 | else 52 | return ele[tmp].val; 53 | } 54 | }; 55 | \end{lstlisting} 56 | -------------------------------------------------------------------------------- /others/java.tex: -------------------------------------------------------------------------------- 1 | \subsection{Java} 2 | \subsubsection{文件操作} 3 | \begin{lstlisting}[language=java] 4 | import java.io.*; 5 | import java.util.*; 6 | import java.math.*; 7 | import java.text.*; 8 | 9 | public class Main 10 | { 11 | 12 | public static void main(String args[]) throws FileNotFoundException, IOException 13 | { 14 | Scanner sc = new Scanner(new FileReader("a.in")); 15 | PrintWriter pw = new PrintWriter(new FileWriter("a.out")); 16 | int n,m; 17 | n=sc.nextInt();//读入下一个INT 18 | m=sc.nextInt(); 19 | 20 | for(ci=1; ci<=c; ++ci) 21 | { 22 | pw.println("Case #"+ci+": easy for output"); 23 | } 24 | 25 | pw.close();//关闭流并释放,这个很重要,否则是没有输出的 26 | sc.close();//关闭流并释放 27 | } 28 | } 29 | \end{lstlisting} 30 | 31 | \subsubsection{优先队列} 32 | \begin{lstlisting}[language=java] 33 | PriorityQueue queue = new PriorityQueue( 1, new Comparator() 34 | { 35 | public int compare( Point a, Point b ) 36 | { 37 | if( a.x < b.x || a.x == b.x && a.y < b.y ) 38 | return -1; 39 | else if( a.x == b.x && a.y == b.y ) 40 | return 0; 41 | else 42 | return 1; 43 | } 44 | }); 45 | \end{lstlisting} 46 | 47 | \subsubsection{Map} 48 | \begin{lstlisting}[language=java] 49 | Map map = new HashMap(); 50 | map.put("sa","dd"); 51 | String str = map.get("sa").toString; 52 | 53 | for(Object obj : map.keySet()){ 54 | Object value = map.get(obj ); 55 | } 56 | \end{lstlisting} 57 | 58 | \subsubsection{sort} 59 | \begin{lstlisting}[language=java] 60 | static class cmp implements Comparator 61 | { 62 | public int compare(Object o1,Object o2) 63 | { 64 | BigInteger b1=(BigInteger)o1; 65 | BigInteger b2=(BigInteger)o2; 66 | return b1.compareTo(b2); 67 | } 68 | } 69 | public static void main(String[] args) throws IOException 70 | { 71 | Scanner cin = new Scanner(System.in); 72 | int n; 73 | n=cin.nextInt(); 74 | BigInteger[] seg = new BigInteger[n]; 75 | for (int i=0;i input 6 | ./sol < input > output.sol 7 | ./bf < input > output.bf 8 | 9 | diff output.sol output.bf 10 | if [ $? -ne 0 ] ; then break; fi 11 | done 12 | \end{lstlisting} -------------------------------------------------------------------------------- /others/readint.tex: -------------------------------------------------------------------------------- 1 | \subsection{整数外挂} 2 | \begin{lstlisting}[language=c++] 3 | int wg; 4 | char ch; 5 | bool ng; 6 | 7 | inline int readint() 8 | { 9 | ch = getchar(); 10 | while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); 11 | if (ch == '-') 12 | { 13 | ng = true; 14 | ch = getchar(); 15 | } 16 | else 17 | ng = false; 18 | wg = ch-'0'; 19 | ch = getchar(); 20 | while (ch >= '0' && ch <= '9') 21 | { 22 | wg = wg*10+ch-'0'; 23 | ch = getchar(); 24 | } 25 | if (ng == true) wg = -wg; 26 | return wg; 27 | } 28 | \end{lstlisting} -------------------------------------------------------------------------------- /others/stl.tex: -------------------------------------------------------------------------------- 1 | \subsection{C++\&STL常用函数} 2 | \subsubsection{lower\_bound/upper\_bound} 3 | 不解释\\ 4 | \begin{lstlisting}[language=c++] 5 | iterator lower_bound(const key_type &key ) 6 | \\`返回一个迭代器,指向键值>= key的第一个元素。` 7 | iterator upper_bound(const key_type &key ) 8 | \\`返回一个迭代器,指向键值> key的第一个元素。` 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | int main () { 16 | int myints[] = {10,20,30,30,20,10,10,20}; 17 | vector v(myints,myints+8); 18 | // 10 20 30 30 20 10 10 20 19 | vector::iterator low,up; 20 | 21 | sort (v.begin(), v.end()); 22 | // 10 10 10 20 20 20 30 30 23 | 24 | low=lower_bound (v.begin(), v.end(), 20); 25 | // 10 10 10 20 20 20 30 30 26 | // ^ 27 | up= upper_bound (v.begin(), v.end(), 20); 28 | // 10 10 10 20 20 20 30 30 29 | // ^ 30 | 31 | cout << "lower_bound at position " << int(low- v.begin()) << endl; 32 | cout << "upper_bound at position " << int(up - v.begin()) << endl; 33 | 34 | return 0; 35 | } 36 | \end{lstlisting} 37 | Output:\\ 38 | \begin{lstlisting}[language=c++] 39 | lower_bound at position 3 40 | upper_bound at position 6 41 | \end{lstlisting} 42 | 43 | \subsubsection{rotate} 44 | 把数组后一半搬到前面\\ 45 | \begin{lstlisting}[language=c++] 46 | template 47 | void rotate ( ForwardIterator first, ForwardIterator middle, 48 | ForwardIterator last ); 49 | \end{lstlisting} 50 | 51 | \subsubsection{nth\_element} 52 | \begin{lstlisting}[language=c++] 53 | template 54 | void nth_element ( RandomAccessIterator first, RandomAccessIterator nth, 55 | RandomAccessIterator last ); 56 | 57 | template 58 | void nth_element ( RandomAccessIterator first, RandomAccessIterator nth, 59 | RandomAccessIterator last, Compare comp ); 60 | \end{lstlisting} 61 | 62 | \subsubsection{bitset} 63 | 取用\\ 64 | \begin{lstlisting}[language=c++] 65 | bitset<4> mybits; 66 | 67 | mybits[1]=1; // 0010 68 | mybits[2]=mybits[1]; // 0110 69 | \end{lstlisting} 70 | 翻转\\ 71 | \begin{lstlisting}[language=c++] 72 | bitset<4> mybits (string("0001")); 73 | 74 | cout << mybits.flip(2) << endl; // 0101 75 | cout << mybits.flip() << endl; // 1010 76 | \end{lstlisting} 77 | 运算\\ 78 | \begin{lstlisting}[language=c++] 79 | bitset<4> first (string("1001")); 80 | bitset<4> second (string("0011")); 81 | 82 | cout << (first^=second) << endl; // 1010 (XOR,assign) 83 | cout << (first&=second) << endl; // 0010 (AND,assign) 84 | cout << (first|=second) << endl; // 0011 (OR,assign) 85 | 86 | cout << (first<<=2) << endl; // 1100 (SHL,assign) 87 | cout << (first>>=1) << endl; // 0110 (SHR,assign) 88 | 89 | cout << (~second) << endl; // 1100 (NOT) 90 | cout << (second<<1) << endl; // 0110 (SHL) 91 | cout << (second>>1) << endl; // 0001 (SHR) 92 | 93 | cout << (first==second) << endl; // false (0110==0011) 94 | cout << (first!=second) << endl; // true (0110!=0011) 95 | 96 | cout << (first&second) << endl; // 0010 97 | cout << (first|second) << endl; // 0111 98 | cout << (first^second) << endl; // 0101 99 | \end{lstlisting} 100 | 101 | \subsubsection{multimap} 102 | 遍历\\ 103 | \begin{lstlisting}[language=c++] 104 | multimap mymm; 105 | multimap::iterator it; 106 | char c; 107 | 108 | mymm.insert(pair('x',50)); 109 | mymm.insert(pair('y',100)); 110 | mymm.insert(pair('y',150)); 111 | mymm.insert(pair('y',200)); 112 | mymm.insert(pair('z',250)); 113 | mymm.insert(pair('z',300)); 114 | 115 | for (c='x'; c<='z'; c++) 116 | { 117 | cout << "There are " << (int)mymm.count(c); 118 | cout << " elements with key " << c << ":"; 119 | for (it=mymm.equal_range(c).first; it!=mymm.equal_range(c).second; ++it) 120 | cout << " " << (*it).second; 121 | cout << endl; 122 | } 123 | /* 124 | Output: 125 | 126 | There are 1 elements with key x: 50 127 | There are 3 elements with key y: 100 150 200 128 | There are 2 elements with key z: 250 300 129 | */ 130 | \end{lstlisting} 131 | 二分查找\\ 132 | \begin{lstlisting}[language=c++] 133 | multimap mymultimap; 134 | multimap::iterator it,itlow,itup; 135 | 136 | mymultimap.insert(pair('a',10)); 137 | mymultimap.insert(pair('b',121)); 138 | mymultimap.insert(pair('c',1001)); 139 | mymultimap.insert(pair('c',2002)); 140 | mymultimap.insert(pair('d',11011)); 141 | mymultimap.insert(pair('e',44)); 142 | 143 | itlow=mymultimap.lower_bound ('b'); // itlow points to b 144 | itup=mymultimap.upper_bound ('d'); // itup points to e (not d) 145 | 146 | // print range [itlow,itup): 147 | for ( it=itlow ; it != itup; it++ ) 148 | cout << (*it).first << " => " << (*it).second << endl; 149 | 150 | /* 151 | Output: 152 | 153 | b => 121 154 | c => 1001 155 | c => 2002 156 | d => 11011 157 | */ 158 | \end{lstlisting} 159 | 删除\\ 160 | \begin{lstlisting}[language=c++] 161 | multimap mymultimap; 162 | multimap::iterator it; 163 | 164 | // insert some values: 165 | mymultimap.insert(pair('a',10)); 166 | mymultimap.insert(pair('b',20)); 167 | mymultimap.insert(pair('b',30)); 168 | mymultimap.insert(pair('c',40)); 169 | mymultimap.insert(pair('d',50)); 170 | mymultimap.insert(pair('d',60)); 171 | mymultimap.insert(pair('e',70)); 172 | mymultimap.insert(pair('f',80)); 173 | 174 | it=mymultimap.find('b'); 175 | mymultimap.erase (it); 176 | // erasing by iterator (1 element) 177 | 178 | mymultimap.erase ('d'); 179 | // erasing by key (2 elements) 180 | 181 | it=mymultimap.find ('e'); 182 | mymultimap.erase ( it, mymultimap.end() ); 183 | // erasing by range 184 | 185 | // show content: 186 | for ( it=mymultimap.begin() ; it != mymultimap.end(); it++ ) 187 | cout << (*it).first << " => " << (*it).second << endl; 188 | 189 | /* 190 | Output: 191 | 192 | a => 10 193 | b => 30 194 | c => 40 195 | */ 196 | \end{lstlisting} -------------------------------------------------------------------------------- /search.tex: -------------------------------------------------------------------------------- 1 | \section{搜索} 2 | \input search/dlx.tex -------------------------------------------------------------------------------- /search/dlx.tex: -------------------------------------------------------------------------------- 1 | \subsection{Dancing Links} 2 | \subsubsection{估价函数} 3 | \begin{lstlisting}[language=c++] 4 | int h() 5 | { 6 | bool vis[100]; 7 | memset(vis,false,sizeof(vis)); 8 | int i,j,k,res=0,mi,col; 9 | while(1) 10 | { 11 | mi=inf; 12 | for(i=R[head]; i!=head&&i<=2*n; i=R[i]) 13 | if(mi>nk[i]&&!vis[i]) 14 | { 15 | mi=nk[i]; 16 | col=i; 17 | } 18 | if(mi==inf) 19 | break; 20 | res++; 21 | vis[col]=true; 22 | for(j=D[col]; j!=col; j=D[j]) 23 | for(k=R[j]; k!=j; k=R[k]) 24 | { 25 | if(C[k]>2*n) 26 | continue; 27 | vis[C[k]]=true; 28 | } 29 | } 30 | return res; 31 | } 32 | \end{lstlisting} 33 | 34 | \subsubsection{DLX} 35 | \begin{lstlisting}[language=c++] 36 | void remove1(int col) 37 | { 38 | int i,j; 39 | L[R[col]]=L[col]; 40 | R[L[col]]=R[col]; 41 | for(i=D[col];i!=col;i=D[i]) 42 | { 43 | L[R[i]]=L[i]; 44 | R[L[i]]=R[i]; 45 | } 46 | } 47 | void remove2(int col) 48 | { 49 | int i,j; 50 | L[R[col]]=L[col]; 51 | R[L[col]]=R[col]; 52 | for(i=D[col];i!=col;i=D[i]) 53 | { 54 | for(j=R[i];j!=i;j=R[j]) 55 | { 56 | U[D[j]]=U[j]; 57 | D[U[j]]=D[j]; 58 | --nk[C[j]]; 59 | } 60 | } 61 | } 62 | void resume1(int col) 63 | { 64 | int i,j; 65 | for(i=U[col];i!=col;i=U[i]) 66 | { 67 | L[R[i]]=i; 68 | R[L[i]]=i; 69 | } 70 | L[R[col]]=col; 71 | R[L[col]]=col; 72 | } 73 | void resume2(int col) 74 | { 75 | int i,j; 76 | for(i=U[col];i!=col;i=U[i]) 77 | { 78 | for(j=L[i];j!=i;j=L[j]) 79 | { 80 | ++nk[C[j]]; 81 | U[D[j]]=j; 82 | D[U[j]]=j; 83 | } 84 | } 85 | L[R[col]]=col; 86 | R[L[col]]=col; 87 | } 88 | int h() 89 | { 90 | bool vis[100]; 91 | memset(vis,false,sizeof(vis)); 92 | int i,j,k,res=0,mi,col; 93 | while(1) 94 | { 95 | mi=inf; 96 | for(i=R[head];i!=head&&i<=2*n;i=R[i]) 97 | if(mi>nk[i]&&!vis[i]) 98 | { 99 | mi=nk[i]; 100 | col=i; 101 | } 102 | if(mi==inf) 103 | break; 104 | res++;vis[col]=true; 105 | for(j=D[col];j!=col;j=D[j]) 106 | for(k=R[j];k!=j;k=R[k]) 107 | { 108 | if(C[k]>2*n) 109 | continue; 110 | vis[C[k]]=true; 111 | } 112 | } 113 | return res; 114 | } 115 | bool DLX(int d,int deep) 116 | { 117 | if(d+h()>deep) return false; 118 | if(R[head]==head||R[head]>2*n) 119 | return true; 120 | if(d>=deep) 121 | return false; 122 | int col,ma=inf; 123 | int i,j; 124 | for(i=R[head];i!=head&&i<=2*n;i=R[i]) 125 | if(nk[i]2*n) 141 | remove2(C[j]); 142 | else 143 | remove1(C[j]); 144 | flag=0; 145 | } 146 | if(DLX(d+1,deep)) 147 | return true; 148 | flag=1; 149 | for(j=L[i];;j=L[j]) 150 | { 151 | if(j==L[i]&&!flag) 152 | break; 153 | if(C[j]>2*n) 154 | resume2(C[j]); 155 | else 156 | resume1(C[j]); 157 | U[D[j]]=j; 158 | D[U[j]]=j; 159 | flag=0; 160 | } 161 | } 162 | resume1(col); 163 | return false; 164 | } 165 | \end{lstlisting} 166 | -------------------------------------------------------------------------------- /string.tex: -------------------------------------------------------------------------------- 1 | \section{字符串处理} 2 | \input string/ACautomaton.tex 3 | \input string/suffixarrays.tex 4 | \input string/suffixtree.tex 5 | \input string/KMP.tex 6 | \input string/eKMP.tex 7 | \input string/Manacher.tex 8 | \input string/palindromes.tex 9 | \input string/smallestrepresention.tex 10 | \input string/ls.tex -------------------------------------------------------------------------------- /string/ACautomaton.tex: -------------------------------------------------------------------------------- 1 | \subsection{*AC自动机} 2 | \subsubsection{指针} 3 | \begin{lstlisting}[language=c++] 4 | const int CHAR=26; 5 | const int TOTLEN=500000; 6 | const int MAXLEN=1000000; 7 | struct Vertex 8 | { 9 | Vertex *fail,*next[CHAR]; 10 | Vertex(){} 11 | Vertex(bool flag)//为什么要这样写? 12 | { 13 | fail=0; 14 | memset(next,0,sizeof(next)); 15 | } 16 | }; 17 | int size; 18 | Vertex vertex[TOTLEN+1]; 19 | void init() 20 | { 21 | vertex[0]=Vertex(0); 22 | size=1; 23 | } 24 | void add(Vertex *pos,int cha) 25 | { 26 | vertex[size]=Vertex(0); 27 | pos->next[cha]=&vertex[size++]; 28 | } 29 | void add(vector s) 30 | { 31 | int l=s.size(); 32 | Vertex *pos=&vertex[0]; 33 | for (int i=0; inext[s[i]]==NULL) 36 | add(pos,s[i]); 37 | pos=pos->next[s[i]]; 38 | } 39 | } 40 | void bfs() 41 | { 42 | queue que; 43 | Vertex *u=&vertex[0]; 44 | for (int i=0; inext[i]!=NULL) 46 | { 47 | que.push(u->next[i]); 48 | u->next[i]->fail=u; 49 | } 50 | else 51 | u->next[i]=u; 52 | u->fail=NULL; 53 | while (!que.empty()) 54 | { 55 | u=que.front(); 56 | que.pop(); 57 | for (int i=0; inext[i]!=NULL) 59 | { 60 | que.push(u->next[i]); 61 | u->next[i]->fail=u->fail->next[i]; 62 | } 63 | else 64 | u->next[i]=u->fail->next[i]; 65 | } 66 | } 67 | \end{lstlisting} 68 | \subsubsection{非指针} 69 | \begin{lstlisting}[language=c++] 70 | struct Trie 71 | { 72 | int next[50][10],fail[50]; 73 | bool end[50]; 74 | int L,root; 75 | 76 | int newNode() 77 | { 78 | for (int i = 0;i < 10;i++) 79 | next[L][i] = -1; 80 | end[L] = false; 81 | return L++; 82 | } 83 | 84 | void Init() 85 | { 86 | L = 0; 87 | root = newNode(); 88 | } 89 | 90 | void Insert(char s[]) 91 | { 92 | int now = root; 93 | for (int i = 0;s[i] != 0;i++) 94 | { 95 | if (next[now][s[i]-'0'] == -1) 96 | next[now][s[i]-'0'] = newNode(); 97 | now = next[now][s[i]-'0']; 98 | } 99 | end[now] = true; 100 | } 101 | 102 | void Build() 103 | { 104 | queue Q; 105 | for (int i = 0;i < 10;i++) 106 | if (next[root][i] == -1) 107 | next[root][i] = root; 108 | else 109 | { 110 | fail[next[root][i]] = root; 111 | Q.push(next[root][i]); 112 | } 113 | while (!Q.empty()) 114 | { 115 | int now = Q.front(); 116 | Q.pop(); 117 | end[now] |= end[fail[now]]; 118 | for (int i = 0;i < 10;i++) 119 | if (next[now][i] == -1) 120 | next[now][i] = next[fail[now]][i]; 121 | else 122 | { 123 | fail[next[now][i]] = next[fail[now]][i]; 124 | Q.push(next[now][i]); 125 | } 126 | } 127 | } 128 | }; 129 | \end{lstlisting} -------------------------------------------------------------------------------- /string/KMP.tex: -------------------------------------------------------------------------------- 1 | \subsection{KMP} 2 | 求A[0..i]的一个后缀最多能匹配B的前缀多长。 3 | 先对B进行自匹配然后与A匹配。 4 | KMP[i]就是对应答案,p[i]+1是B[0..i]的一个后缀最多能匹配B的前缀多长。 5 | \begin{lstlisting}[language=c++] 6 | //自匹配过程 7 | int j; 8 | p [0] = j = -1; 9 | for ( int i = 1; i < lb; i++) 10 | { 11 | while (j >= 0 && b[j + 1] != b[i]) j = p[j]; 12 | if (b[j + 1] == b[i]) j ++; 13 | p[i] = j; 14 | } 15 | //下面是匹配过程 16 | j = -1; 17 | for ( int i = 0; i < la; i++) 18 | { 19 | while (j >= 0 && b[j + 1] != a[i]) j = p[j]; 20 | if (b[j + 1] == a[i]) j ++; 21 | KMP[i] = j + 1; 22 | } 23 | \end{lstlisting} -------------------------------------------------------------------------------- /string/Manacher.tex: -------------------------------------------------------------------------------- 1 | \subsection{Manacher} 2 | \begin{lstlisting}[language=c++] 3 | const int maxn = 110000; 4 | 5 | char Ma[maxn*2]; 6 | int Mp[maxn*2]; 7 | void Manacher(char s[],int len) 8 | { 9 | int l = 0; 10 | Ma[l++] = '.'; 11 | Ma[l++] = ','; 12 | for (int i = 0;i < len;i++) 13 | { 14 | Ma[l++] = s[i]; 15 | Ma[l++] = ','; 16 | } 17 | Ma[l] = 0; 18 | int pnow = 0,pid = 0; 19 | for (int i = 1;i < l;i++) 20 | { 21 | if (pnow > i) 22 | Mp[i] = min(Mp[2*pid-i],pnow-i); 23 | else 24 | Mp[i] = 1; 25 | for (;Ma[i-Mp[i]] == Ma[i+Mp[i]];Mp[i]++); 26 | if (i+Mp[i] > pnow) 27 | { 28 | pnow = i+Mp[i]; 29 | pid = i; 30 | } 31 | } 32 | } 33 | /* 34 | abaaba 35 | . , a , b , a , a , b , a , 36 | 0 1 2 1 4 1 2 7 2 1 4 1 2 1 37 | */ 38 | \end{lstlisting} -------------------------------------------------------------------------------- /string/eKMP.tex: -------------------------------------------------------------------------------- 1 | \subsection{e-KMP} 2 | 求A[i..len-1]和B的最长公共前缀有多长。 3 | 先对B进行自匹配然后与A匹配。 4 | eKMP[i]就是对应答案。p[i]是B[i..len-1]和B的最长公共前缀有多长。 5 | \begin{lstlisting}[language=c++] 6 | //自匹配过程 7 | int j = 0; 8 | while (j < lb && b[j] == b[j + 1]) 9 | j++; 10 | p[0] = lb, p[1] = j; 11 | int k = 1; 12 | for (int i = 2; i < lb; i++) 13 | { 14 | int Len = k + p[k] - 1, L = p[i - k]; 15 | if (L < Len - i + 1) 16 | p[i] = L; 17 | else 18 | { 19 | j = max(0, Len - i + 1); 20 | while (i + j < lb && b[i + j] == b[j]) 21 | j++; 22 | p[i] = j, k = i; 23 | } 24 | } 25 | //下面是匹配过程 26 | j = 0; 27 | while (j < la && j < lb && a[j] == b[j]) 28 | j++; 29 | eKMP[0] = j; 30 | k = 0; 31 | for (int i = 1; i < la; i++) 32 | { 33 | int Len = k + eKMP[k] - 1, L = p[i - k]; 34 | if (L < Len - i + 1) 35 | eKMP[i] = L; 36 | else 37 | { 38 | j = max(0, Len - i + 1); 39 | while (i + j < la && j < lb && a[i + j] == b[j]) 40 | j++; 41 | eKMP[i] = j, k = i; 42 | } 43 | } 44 | \end{lstlisting} -------------------------------------------------------------------------------- /string/ls.tex: -------------------------------------------------------------------------------- 1 | \subsection{带*通配符的匹配} 2 | \begin{lstlisting}[language=c++] 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | char a[110],b[110],sp[110][110],tot,place[110]; 10 | int n,la,lb,ll; 11 | 12 | bool check(int id,int pos) 13 | { 14 | for (int i = 0;sp[id][i] != 0;i++) 15 | if (b[pos+i] != sp[id][i]) 16 | return false; 17 | return true; 18 | } 19 | 20 | bool check() 21 | { 22 | lb = strlen(b); 23 | int pre = 0; 24 | for (int i = 0;i < tot;i++) 25 | { 26 | bool find = false; 27 | for (int j = pre;j < lb;j++) 28 | if (check(i,j) == true) 29 | { 30 | place[i] = j; 31 | pre = place[i]+1; 32 | find = true; 33 | break; 34 | } 35 | if (find == false) return false; 36 | } 37 | if (a[0] != '*') 38 | if (place[0] != 0) 39 | return false; 40 | if (a[la-1] != '*') 41 | if (check(tot-1,lb-ll) == false) 42 | return false; 43 | return true; 44 | } 45 | 46 | int main() 47 | { 48 | while (scanf("%s",a) != EOF) 49 | { 50 | tot = 0; 51 | for (int i = 0;a[i] != 0;i++) 52 | if (a[i] != '*') 53 | { 54 | int j; 55 | for (j = i;a[j] != 0 && a[j] != '*';j++) 56 | sp[tot][j-i] = a[j]; 57 | sp[tot++][j-i] = 0; 58 | i = j; 59 | } 60 | la = strlen(a); 61 | ll = strlen(sp[tot-1]); 62 | scanf("%d",&n); 63 | for (int i = 0;i < n;i++) 64 | { 65 | scanf("%s",b); 66 | if (check() == true) 67 | puts(b); 68 | } 69 | } 70 | return 0; 71 | } 72 | /* 73 | Sample Input 1 74 | *.* 75 | 4 76 | main.c 77 | a.out 78 | readme 79 | yacc 80 | 81 | Sample Input 2 82 | *a*a*a 83 | 4 84 | aaa 85 | aaaaa 86 | aaaaax 87 | abababa 88 | 89 | Sample Output 1 90 | main.c 91 | a.out 92 | 93 | Sample Output 2 94 | aaa 95 | aaaaa 96 | abababa 97 | */ 98 | \end{lstlisting} 99 | -------------------------------------------------------------------------------- /string/palindromes.tex: -------------------------------------------------------------------------------- 1 | \subsection{不同回文串} 2 | 往hash表中插入新东西的时候就说明找到了一个新回文字串\\ 3 | 一共$O(n)$个 4 | \begin{lstlisting}[language=c++] 5 | typedef unsigned int uint; 6 | 7 | const int maxn = 110000; 8 | 9 | char Ma[maxn*2]; 10 | int Mp[maxn*2]; 11 | void Manacher(char s[],int len) 12 | { 13 | int l = 0; 14 | Ma[l++] = '.'; 15 | Ma[l++] = ','; 16 | for (int i = 0; i < len; i++) 17 | { 18 | Ma[l++] = s[i]; 19 | Ma[l++] = ','; 20 | } 21 | Ma[l] = 0; 22 | int pnow = 0,pid = 0; 23 | for (int i = 1; i < l; i++) 24 | { 25 | if (pnow > i) 26 | Mp[i] = min(Mp[2*pid-i],pnow-i); 27 | else 28 | Mp[i] = 1; 29 | for (; Ma[i-Mp[i]] == Ma[i+Mp[i]]; Mp[i]++); 30 | if (i+Mp[i] > pnow) 31 | { 32 | pnow = i+Mp[i]; 33 | pid = i; 34 | } 35 | } 36 | } 37 | 38 | char s[maxn*2]; 39 | int len; 40 | int p[maxn*2]; 41 | const int muts = 129; 42 | uint sum[maxn]; 43 | uint mutpower[maxn]; 44 | 45 | struct hash_map 46 | { 47 | const static int mod = 300007; 48 | int head[mod]; 49 | struct hash_tables 50 | { 51 | uint key1; 52 | int key2; 53 | int next; 54 | } ele[maxn*10]; 55 | int N; 56 | void init() 57 | { 58 | memset(head,-1,sizeof(head)); 59 | N = 0; 60 | } 61 | int totlen[mod]; 62 | void clear() 63 | { 64 | for (int i = 0; i < N; i++) 65 | head[ele[i].key1%mod] = -1; 66 | N = 0; 67 | } 68 | int find(uint x,int len) 69 | { 70 | int hashcode = x%mod; 71 | for (int i = head[hashcode]; i != -1; i = ele[i].next) 72 | if (ele[i].key1 == x && ele[i].key2 == len) 73 | return i; 74 | return -1; 75 | } 76 | void insert(uint x,int len) 77 | { 78 | int tmp = x%mod; 79 | ele[N].key1 = x; 80 | ele[N].key2 = len; 81 | ele[N].next = head[tmp]; 82 | head[tmp] = N++; 83 | } 84 | }; 85 | 86 | hash_map hash; 87 | 88 | uint gethashcode(int l,int r) 89 | { 90 | uint ret; 91 | ret = sum[r]; 92 | if (l) 93 | ret -= sum[l-1]*mutpower[r-l+1]; 94 | return ret; 95 | } 96 | 97 | int calc(char s[]) 98 | { 99 | len = strlen(s); 100 | Manacher(s,len); 101 | 102 | sum[0] = s[0]; 103 | for (int i = 1; i < len; i++) 104 | sum[i] = sum[i-1]*muts+s[i]; 105 | 106 | int res = 0; 107 | uint tmp; 108 | int nt = 0; 109 | hash.clear(); 110 | //odd 111 | for (int i = 0; i < len; i++) 112 | if (Mp[i*2+2]%2 == 0) 113 | { 114 | int pl = Mp[i*2+2]/2; 115 | if (i+pl < nt || pl == 0) continue; 116 | for (int j = i-pl+1; j <= i; j++) 117 | { 118 | tmp = gethashcode(j,i); 119 | if (hash.find(tmp,i-j+1) != -1) break; 120 | hash.insert(tmp,i-j+1); 121 | } 122 | nt = i+pl; 123 | } 124 | res += hash.N; 125 | 126 | nt = 0; 127 | hash.clear(); 128 | //even 129 | for (int i = 0; i < len; i++) 130 | if (Mp[i*2+3] > 1) 131 | { 132 | int pl = Mp[i*2+3]/2; 133 | if (i+pl < nt || pl == 0) continue; 134 | for (int j = i-pl+1; j <= i; j++) 135 | { 136 | tmp = gethashcode(j,i); 137 | if (hash.find(tmp,i-j+1) != -1) break; 138 | hash.insert(tmp,i-j+1); 139 | } 140 | nt = i+pl; 141 | } 142 | res += hash.N; 143 | return res; 144 | } 145 | 146 | int main() 147 | { 148 | mutpower[0] = 1; 149 | for (int i = 1; i < maxn; i++) 150 | mutpower[i] = mutpower[i-1]*muts; 151 | hash.init(); 152 | 153 | int totcas; 154 | scanf("%d",&totcas); 155 | for (int cas = 1; cas <= totcas; cas++) 156 | { 157 | scanf("%s",s); 158 | 159 | printf("Case #%d: %d\n",cas,calc(s)); 160 | } 161 | return 0; 162 | } 163 | \end{lstlisting} 164 | -------------------------------------------------------------------------------- /string/smallestrepresention.tex: -------------------------------------------------------------------------------- 1 | \subsection{*字符串最小表示法} 2 | \begin{lstlisting}[language=c++] 3 | int Gao(char a[],int len) 4 | { 5 | int i = 0,j = 1,k = 0; 6 | while (i < len && j < len && k < len) 7 | { 8 | int cmp = a[(j+k)%len]-a[(i+k)%len]; 9 | if (cmp == 0) 10 | k++; 11 | else 12 | { 13 | if (cmp > 0) 14 | j += k+1; 15 | else 16 | i += k+1; 17 | if (i == j) j++; 18 | k = 0; 19 | } 20 | } 21 | return min(i,j); 22 | } 23 | \end{lstlisting} -------------------------------------------------------------------------------- /string/suffixarrays.tex: -------------------------------------------------------------------------------- 1 | \subsection{后缀数组} 2 | \subsubsection{DC3} 3 | 所有下标都是0~n-1,height[0]无意义。 4 | \begin{lstlisting}[language=c++] 5 | //所有相关数组都要开三倍 6 | const int maxn = 300010; 7 | # define F(x) ((x)/3+((x)%3==1?0:tb)) 8 | # define G(x) ((x)= 0; i--) b[--ws[wv[i]]] = a[i]; 29 | return; 30 | } 31 | void dc3(int *r, int *sa, int n, int m) 32 | { 33 | int i, j, *rn = r + n; 34 | int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p; 35 | r[n] = r[n + 1] = 0; 36 | for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i; 37 | sort(r + 2, wa, wb, tbc, m); 38 | sort(r + 1, wb, wa, tbc, m); 39 | sort(r, wa, wb, tbc, m); 40 | for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) 41 | rn[F(wb[i])] = c0(r, wb[i - 1], wb[i]) ? p - 1 : p++; 42 | if (p < tbc) dc3(rn, san, tbc, p); 43 | else for (i = 0; i < tbc; i++) san[rn[i]] = i; 44 | for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3; 45 | if (n % 3 == 1) wb[ta++] = n - 1; 46 | sort(r, wb, wa, ta, m); 47 | for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; 48 | for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) 49 | sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; 50 | for (; i < ta; p++) sa[p] = wa[i++]; 51 | for (; j < tbc; p++) sa[p] = wb[j++]; 52 | } 53 | //`str和sa也要三倍` 54 | void da(int str[],int sa[],int rank[],int height[],int n,int m) 55 | { 56 | for (int i = n; i < n * 3; i++) 57 | str[i] = 0; 58 | dc3 (str , sa , n + 1 , m); 59 | int i, j, k; 60 | for (i = 0; i < n; i++) 61 | { 62 | sa[i] = sa[i + 1]; 63 | rank[sa[i]] = i; 64 | } 65 | for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k) 66 | if (rank[i] > 0) 67 | for (k ? k-- : 0 , j = sa[rank[i] - 1]; 68 | i + k < n && j + k < n && str[i + k] == str[j + k]; 69 | k++); 70 | } 71 | \end{lstlisting} 72 | 73 | \subsubsection{DA} 74 | 这份似乎就没啥要注意的了。 75 | \begin{lstlisting}[language=c++] 76 | const int maxn = 200010; 77 | int wx[maxn],wy[maxn],*x,*y,wss[maxn],wv[maxn]; 78 | 79 | bool cmp(int *r,int n,int a,int b,int l) 80 | { 81 | return a+l=0; i--)sa[--wss[x[i]]]=i; 92 | for(j=1,p=1; p=0)y[p++]=sa[i]-j; 96 | for(i=0; i=0; i--)sa[--wss[wv[i]]]=y[i]; 101 | for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0; i0) 107 | for(k?k--:0,j=sa[rank[i]-1]; 108 | i+k < n && j+k < n && str[i+k]==str[j+k]; 109 | k++); 110 | } 111 | \end{lstlisting} 112 | 113 | \subsubsection{调用} 114 | 注意几个数组的下标是不同的 115 | \begin{lstlisting}[language=c++] 116 | char s[maxn]; 117 | int str[maxn],sa[maxn],rank[maxn],height[maxn]; 118 | 119 | int main() 120 | { 121 | scanf("%s",s); 122 | int len = strlen(s); 123 | for (int i = 0;i <= len;i++) 124 | str[i] = s[i]; 125 | da(str,sa,rank,height,len,128); 126 | 127 | for (int i = 0;i < len;i++) 128 | { 129 | printf("sa= %d,height= %d,s= %s\n",sa[i],height[i],s+sa[i]); 130 | } 131 | return 0; 132 | } 133 | \end{lstlisting} 134 | 135 | \subsubsection{最长公共前缀} 136 | 记得不要忘记调用lcpinit! 137 | \begin{lstlisting}[language=c++] 138 | int f[maxn][20]; 139 | int lent[maxn]; 140 | void lcpinit() 141 | { 142 | int i,j; 143 | int n = len,k = 1,l = 0; 144 | for (i = 0; i < n; i++) 145 | { 146 | f[i][0] = height[i]; 147 | if (i+1 > k*2) 148 | { 149 | k *= 2; 150 | l++; 151 | } 152 | lent[i+1] = l; 153 | } 154 | for (j = 1; (1< y) swap(x,y); 161 | if (x == y) 162 | return x-sa[x];//自己和自己lcp当然是自己的长度啦 163 | x++; 164 | int k = lent[y-x+1]; 165 | return min(f[x][k],f[y-(1<>1; 179 | cp = lcp(mid,pos); 180 | if (cp < comlen) 181 | l = mid+1; 182 | else 183 | r = mid; 184 | } 185 | pl = l; 186 | 187 | l = pos; 188 | r = len-1; 189 | while (l < r) 190 | { 191 | mid = l+r+1>>1; 192 | cp = lcp(pos,mid); 193 | if (cp < comlen) 194 | r = mid-1; 195 | else 196 | l = mid; 197 | } 198 | pr = l; 199 | } 200 | \end{lstlisting} -------------------------------------------------------------------------------- /template.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper ]{article} 2 | \usepackage{CJKutf8} 3 | \usepackage{graphicx} 4 | \usepackage{amsmath} 5 | \usepackage{xcolor} 6 | \usepackage{type1cm} 7 | \usepackage{booktabs} 8 | \usepackage{geometry} 9 | %\usepackage[landscape]{geometry} 10 | \geometry{left=3cm,right=1cm,top=1.5cm,bottom=2cm,headsep=0.2cm} 11 | 12 | \usepackage{courier} 13 | %\usepackage{time} 14 | %\usepackage{charter} 15 | 16 | \usepackage{fancyhdr} 17 | 18 | \usepackage{listings} 19 | 20 | \lstset{ 21 | breaklines=true, 22 | tabsize=2, 23 | basicstyle=\ttfamily\normalsize, 24 | numbers=left, 25 | numberstyle=\normalsize, 26 | %keywordstyle=\color{blue!70}, 27 | commentstyle=\ttfamily\normalsize, 28 | frame=leftline, 29 | %rulesepcolor=\color{red!20!green!20!blue!20}, 30 | escapeinside=``, 31 | extendedchars=false 32 | } 33 | \usepackage[dvipdfmx, 34 | CJKbookmarks=true, 35 | colorlinks, 36 | linkcolor=black, 37 | anchorcolor=black, 38 | citecolor=black]{hyperref} 39 | \AtBeginDvi{\special{pdf:tounicode UTF8-UCS2}} 40 | 41 | \begin{document} 42 | \begin{CJK}{UTF8}{gbsn} 43 | \pagestyle{fancy} 44 | \lhead{} 45 | \chead{} 46 | \rhead{\bfseries ACM Template} 47 | \lfoot{\bfseries UESTC\_Lasagne} 48 | \cfoot{} 49 | \rfoot{\bfseries\thepage} 50 | \renewcommand{\headrulewidth}{0.4pt} 51 | \renewcommand{\footrulewidth}{0.4pt} 52 | 53 | \newgeometry{left=1cm,right=1cm,top=1.5cm,bottom=1.5cm} 54 | \begin{titlepage} 55 | ~ 56 | \clearpage 57 | \pagestyle{empty} 58 | 59 | \begin{center} 60 | ~\\[160pt] 61 | 62 | \hrule\ \\[8pt] 63 | \fontsize{48pt}{\baselineskip}\selectfont \textsc{ACM Template}\\[8pt] 64 | \hrule\ \\[340pt] 65 | 66 | \huge UESTC\_Lasagne\\[8pt] 67 | \Large Last build at \today 68 | \end{center} 69 | \end{titlepage} 70 | 71 | \restoregeometry 72 | 73 | \tableofcontents 74 | \clearpage 75 | 76 | \input todolist.tex 77 | \clearpage 78 | 79 | \input notice.tex 80 | \clearpage 81 | 82 | \input string.tex 83 | \clearpage 84 | 85 | \input math.tex 86 | \clearpage 87 | 88 | \input datastructure.tex 89 | \clearpage 90 | 91 | \input graph.tex 92 | \clearpage 93 | 94 | \input geometric.tex 95 | \clearpage 96 | 97 | \input search.tex 98 | \clearpage 99 | 100 | \input dp.tex 101 | \clearpage 102 | 103 | \input others.tex 104 | \clearpage 105 | 106 | \end{CJK} 107 | \end{document} 108 | -------------------------------------------------------------------------------- /template_xelatex.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper]{article} 2 | \usepackage{mathpazo} 3 | \usepackage{xeCJK} 4 | \usepackage{pstricks,pst-node,pst-tree} 5 | 6 | %\setsansfont{Inconsolata} 7 | %\setsansfont{DejaVu Sans Mono} 8 | \setsansfont{Source Code Pro} 9 | 10 | \setCJKmainfont{SimHei} 11 | \setCJKsansfont{SimHei} 12 | \setCJKmonofont{SimHei} 13 | 14 | \usepackage{graphicx} 15 | \usepackage{amsmath} 16 | \usepackage{xcolor} 17 | \usepackage{type1cm} 18 | \usepackage{booktabs} 19 | \usepackage{geometry} 20 | %\usepackage[landscape]{geometry} 21 | \geometry{left=3cm,right=1cm,top=1.5cm,bottom=2cm,headsep=0.2cm} 22 | 23 | \usepackage{courier} 24 | %\usepackage{time} 25 | %\usepackage{charter} 26 | 27 | \usepackage{fancyhdr} 28 | 29 | \usepackage{listings} 30 | 31 | \lstset{ 32 | breaklines=true, 33 | tabsize=2, 34 | basicstyle=\sf\normalsize, 35 | numberstyle=\sf\normalsize, 36 | commentstyle=\sf\normalsize, 37 | numbers=left, 38 | %keywordstyle=\color{blue!70}, 39 | frame=leftline, 40 | %rulesepcolor=\color{red!20!green!20!blue!20}, 41 | escapeinside=``, 42 | extendedchars=false 43 | } 44 | \usepackage[CJKbookmarks=true, 45 | colorlinks, 46 | linkcolor=black, 47 | anchorcolor=black, 48 | citecolor=black]{hyperref} 49 | \AtBeginDvi{\special{pdf:tounicode UTF8-UCS2}} 50 | 51 | \usepackage{indentfirst} 52 | \setlength{\parindent}{0em} 53 | 54 | \begin{document} 55 | \pagestyle{fancy} 56 | \lhead{} 57 | \chead{} 58 | \rhead{\bfseries ACM Template} 59 | \lfoot{\bfseries UESTC\_Lasagne} 60 | \cfoot{} 61 | \rfoot{\bfseries\thepage} 62 | \renewcommand{\headrulewidth}{0.4pt} 63 | \renewcommand{\footrulewidth}{0.4pt} 64 | 65 | \newgeometry{left=1cm,right=1cm,top=1.5cm,bottom=1.5cm} 66 | \begin{titlepage} 67 | ~ 68 | \clearpage 69 | \pagestyle{empty} 70 | 71 | \begin{center} 72 | ~\\[160pt] 73 | 74 | \hrule\ \\[8pt] 75 | \fontsize{48pt}{\baselineskip}\selectfont \textsc{ACM Template}\\[8pt] 76 | \hrule\ \\[340pt] 77 | 78 | \huge UESTC\_Lasagne\\[8pt] 79 | \Large Last build at \today 80 | \end{center} 81 | \end{titlepage} 82 | 83 | \restoregeometry 84 | 85 | \tableofcontents 86 | \clearpage 87 | 88 | %\input todolist.tex 89 | %\clearpage 90 | 91 | \input notice.tex 92 | \clearpage 93 | 94 | \input string.tex 95 | \clearpage 96 | 97 | \input math.tex 98 | \clearpage 99 | 100 | \input datastructure.tex 101 | \clearpage 102 | 103 | \input graph.tex 104 | \clearpage 105 | 106 | \input geometric.tex 107 | \clearpage 108 | 109 | \input search.tex 110 | \clearpage 111 | 112 | \input dp.tex 113 | \clearpage 114 | 115 | \input others.tex 116 | \clearpage 117 | 118 | \end{document} 119 | -------------------------------------------------------------------------------- /todolist.tex: -------------------------------------------------------------------------------- 1 | \section{To Do List} 2 | 所有带*的内容。。。\\ 3 | \\ 4 | 可以从原来的模板里面继承一些好东西过来。\\ 5 | \\ 6 | set,map,multiset等的搞基用法,以及注意事项。\\ 7 | \\ 8 | 生成树计数\\ --------------------------------------------------------------------------------