Forever Young

「笔记」CSP考前复习

前言

因为loceaner太菜了,他什么东西都不会
所以他打算学一个东西就记录一下
不过因为他很菜,所以他不会写原理……
而且,他希望在2019CSP之前不会断更
就酱紫,就是写给他自己的……因为他太菜了

基础算法

小技巧

\[\sum_{i = 0}^{x}C(x, i)* C(y, i) = C(x + y, x) \]

使用负数下标

如何使用负数下标呢?
让数组前面有东西

int y[100];
int *z = y + 50;

这样的话调用\(z[-50]\)就变成了调用\(y[0]\)

z[-50] = y[0];

然后这样就可以实现调用啦~

其实还有一个更暴力的方法:用\(map\)

\(map\)\(\log n\)\(map\)
\(unordered\_map\)\(O(1)\)\(map\)(到\(c++11\)才会有)

二维前缀和

//知识点:二维前缀和
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 1000;

int n, m;
int a[N][N], b[N][N];

int main() {
  n = read(), m = read();
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= n; j++) {
      a[i][j] = read();
      b[i][j] = a[i][j] + b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
    }
  }
  for(int i, u1, v1, u2, v2; i <= m; i++) {
    u1 = read(), v1 = read(), u2 = read(), v2 = read();
    cout << b[u2][v2] - b[u1 - 1][v2] - b[u2][v1 - 1] + b[u1 - 1][v1 - 1] << '\n';
  } 
  return 0;
}

三分法

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const double eps = 1e-6;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n;
double l, r, a[A];


double f(double x) {
  double ans = 0;
  for(int i = 1; i <= n + 1; i++) ans = ans * x + a[i];
  return ans;
}

int main() {
  n = read(); scanf("%lf%lf", &l, &r);
  for(int i = 1; i <= n + 1; i++) scanf("%lf", &a[i]);
  while(r - l >= eps) {
    double qwq = (r - l) / 3.0, lmid = l + qwq, rmid = r - qwq;
    if(f(lmid) > f(rmid)) r = rmid; 
    else l = lmid;
  }
  printf("%.5lf", l);
  return 0;
}

二维差分

//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 1e3 + 11;

int n, m, a[N][N];

int main() {
  n = read(), m = read();
  for(int i = 1, u1, u2, v1, v2; i <= m; i++) {
    u1 = read(), v1 = read(), u2 = read(), v2 = read();
    a[u1][v1] += 1;
    a[u2 + 1][v2 + 1] += 1;
    a[u2 + 1][v1] -= 1;
    a[u1][v2 + 1] -= 1;
  }
  //C[x1][y1] += x ,  C[x2 + 1][y2 + 1] += x ,  C[x1][y2 + 1] -= x , C[x2 + 1][y1] -= x;
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= n; j++) {
      a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];;
    } 
  }
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= n; j++) {
      cout << a[i][j] << ' ';
    }
    cout << '\n';
  }
  return 0;
}

归并排序

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

int n, m, a[A], b[A];

void solve(int l, int r) {
  if(l == r) return;
  int mid = (l + r) >> 1;
  solve(l, mid), solve(mid + 1, r);
  int i = l, j = mid + 1, k = l;
  while(i <= mid && j <= r) {
    if(a[i] <= a[j]) b[k++] = a[i++];
    else b[k++] = a[j++];
  }
  while(i <= mid) b[k++] = a[i++]; 
  while(j <= r) b[k++] = a[j++];
  for(int i = l; i <= r; i++) a[i] = b[i];
}

int main() {
//  freopen("a.in", "r", stdin);
  n = read();
  for(int i = 1; i <= n; i++) a[i] = read();
  solve(1, n);
  for(int i = 1; i <= n; i++) cout << a[i] << ' ';
  return 0;
}

排序不等式

给定3组数\(a, b, c\)
\(a[1]\)$a[n]$,$b[1]$\(b[n]\),\(c[1]\)~\(c[n]\)
其中\(c[1]\)$c[n]$是$b[1]$\(b[n]\)的乱序排列
\(a[1]*b[n]+a[2]*b[n-1]+...<=a[1]*c[1]+a[2]*c[2]+...<=a[1]*b[1]+a[2]*b[2]+...\)
即:逆序和 <= 乱序和 <= 正序和

关于\(long\ long\)

在日常的题目中,一定要看好数据范围,如果会爆\(int\)的话,不要忘记开\(long long\)(无数次被坑!!)

高精度模板

最让人烦的就是高精度了,某些题并不难,但是要写高精。。烦\(\color{white}{(ps:板子来自lfd)}\)

namespace BigInteger {
  struct Big_integer {
    int d[10005], len;
    void clean() {while(len > 1 and !d[len - 1]) len--;}
    Big_integer() {memset(d, 0, sizeof d);len = 1;}
    Big_integer(int num) {*this = num;}
    Big_integer operator = (const char* num) {
      memset(d, 0, sizeof d);
      len = strlen(num);
      for (int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
      clean();
      return *this;
    }
    Big_integer operator = (int num) {
      char s[10005];
      sprintf(s, "%d", num);
      *this = s;
      return *this;
    }
    Big_integer operator * (const Big_integer &b) const {
      int i, j;
      Big_integer c;
      c.len = len + b.len;
      for (j = 0; j < b.len; j++)
        for (i = 0; i < len; i++)
          c.d[i + j] += d[i] * b.d[j];
      for (i = 0; i < c.len - 1; i++) c.d[i + 1] += c.d[i] / 10, c.d[i] %= 10;
      c.clean();
      return c;
    }
    Big_integer operator / (const int &b) {
      int i, j, a = 0;
      Big_integer c = *this;
      for (i = len - 1; i >= 0; i--) {
        a = a * 10 + d[i];
        for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
        c.d[i] = j;
        a = a - b * j;
      }
      c.clean();
      return c;
    }
    bool operator < (const Big_integer &b) const {
      if (len != b.len) return len < b.len;
      for (int i = len - 1; i >= 0; i--)
        if (d[i] != b.d[i])
          return d[i] < b.d[i];
      return false;
    }
    string str() const {
      char s[10005];
      for (int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
      return s;
    }
  };
  istream& operator >> (istream& in, Big_integer &x) {
    string s;
    in >> s;
    x = s.c_str();
    return in;
  }
  ostream& operator << (ostream& out, const Big_integer &x) {
    out << x.str();
    return out;
  }
}
using namespace BigInteger;

数据结构

树状数组

单点修改,区间查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, c[B];

void update(int x, int k) {
  while(x <= n) {
    c[x] += k;
    x += lowbit(x);
  }
}

int query(int x) {
  int ans = 0;
  while(x) {
    ans += c[x];
    x -= lowbit(x);
  }
  return ans;
}

int main() {
  n = read(), m = read();
  for(int i = 1, a; i <= n; i++) {
    a = read();
    update(i, a);
  }
  while(m--) {
    int opt = read(), x = read(), y = read();
    if(opt == 1) update(x, y);
    else cout << query(y) - query(x - 1) << '\n';
  }
  return 0;
}

区间修改,单点查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) (x & (-x))
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, c[B], a[B];

void update(int x, int k) {
  while(x <= n) {
    c[x] += k;
    x += lowbit(x);
  }
}

int query(int x) {
  int ans = 0;
  while(x) {
    ans += c[x];
    x -= lowbit(x);
  }
  return ans;
}

int main() {
  n = read(), m = read();
  for(int i = 1; i <= n; i++) a[i] = read();
  while(m--) {
    int opt = read(), x = read(), y, k;
    if(opt == 1) y = read(), k = read(), update(x, k), update(y + 1, -k);
    else cout << a[x] + query(x) << '\n';
  }
  return 0;
}

线段树

区间修改,区间查询

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m;

namespace Seg {
  #define lson rt << 1
  #define rson rt << 1 | 1
  struct tree {
    int l, r, w, lazy;
  } t[A << 2];
  inline void pushup(int rt) { t[rt].w = t[lson].w + t[rson].w; }
  inline void pushdown(int rt) {
    t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy;
    t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy;
    t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy;
    t[rt].lazy = 0;
  }
  void build(int rt, int l, int r) {
    t[rt].l = l, t[rt].r = r;
    if(l == r) { t[rt].w = read(); return; }
    int mid = (l + r) >> 1;
    build(lson, l, mid), build(rson, mid + 1, r);
    pushup(rt); return;
  }
  void update(int rt, int l, int r, int val) {
    if(l <= t[rt].l && t[rt].r <= r) {
      t[rt].lazy += val;
      t[rt].w += (t[rt].r - t[rt].l + 1) * val;
      return;
    }
    if(t[rt].lazy) pushdown(rt); 
    int mid = (t[rt].l + t[rt].r) >> 1;
    if(l <= mid) update(lson, l, r, val);
    if(r > mid) update(rson, l, r, val);
    pushup(rt); return;
  }
  int query(int rt, int l, int r) {
    if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w; }
    if(t[rt].lazy) pushdown(rt); 
    int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
    if(l <= mid) ans += query(lson, l, r);
    if(r > mid) ans += query(rson, l, r);
    return ans;
  }
}

signed main() {
  n = read(), m = read();
  Seg::build(1, 1, n);
  while(m--) {
    int opt = read(), x = read(), y = read(), k;
    if(opt == 1) k = read(), Seg::update(1, x, y, k);
    else cout << Seg::query(1, x, y) << '\n';
  }
  return 0;
}

区间加,区间乘,区间求和

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, mod;

namespace Seg {
  #define lson rt << 1
  #define rson rt << 1 | 1
  struct tre {
    int l, r, w, lazy1, lazy2;
  } t[A << 2];
  inline void pushup(int rt) {
    t[rt].w = (t[lson].w + t[rson].w) % mod;
  }
  inline void tag1(int rt, int val) {
    t[rt].lazy1 *= val, t[rt].lazy2 *= val;
    t[rt].lazy1 %= mod, t[rt].lazy2 %= mod;    
    t[rt].w *= val, t[rt].w %= mod;
  }
  inline void tag2(int rt, int val) {
    t[rt].lazy2 += val; t[rt].lazy2 %= mod;
    t[rt].w += (t[rt].r - t[rt].l + 1) * val, t[rt].w %= mod;
  }
  inline void pushdown(int rt) {
    if(t[rt].lazy1 != 1) {
      tag1(lson, t[rt].lazy1);
      tag1(rson, t[rt].lazy1);
      t[rt].lazy1 = 1;
    }
    if(t[rt].lazy2) {
      tag2(lson, t[rt].lazy2);
      tag2(rson, t[rt].lazy2);
      t[rt].lazy2 = 0;
    }
  }
  inline void build(int rt, int l, int r) {
    t[rt].l = l, t[rt].r = r, t[rt].lazy1 = 1, t[rt].lazy2 = 0;
    if(l == r) { t[rt].w = read(); return; }
    int mid = (l + r) >> 1;
    build(lson, l, mid), build(rson, mid + 1, r);
    pushup(rt); return;
  }
  inline void mul(int rt, int l, int r, int val) {
    if(l <= t[rt].l && t[rt].r <= r) return tag1(rt, val);
    pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1;
    if(l <= mid) mul(lson, l, r, val);
    if(r > mid) mul(rson, l, r, val);
    pushup(rt); return;
  }
  inline void update(int rt, int l, int r, int val) {
    if(l <= t[rt].l && t[rt].r <= r) return tag2(rt, val);
    pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1;
    if(l <= mid) update(lson, l, r, val);
    if(r > mid) update(rson, l, r, val);
    pushup(rt); return;
  }
  inline int query(int rt, int l, int r) {
    if(l <= t[rt].l && t[rt].r <= r) { return t[rt].w % mod; }
    pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
    if(l <= mid) ans += query(lson, l, r), ans %= mod;
    if(r > mid) ans += query(rson, l, r), ans %= mod;
    return ans % mod;
  }
}

signed main() {
  n = read(), m = read(), mod = read();
  Seg::build(1, 1, n);
  while(m--) {
    int opt = read(), x = read(), y = read(), k;
    if(opt == 1) k = read() % mod, Seg::mul(1, x, y, k);
    else if(opt == 2) k = read() % mod, Seg::update(1, x, y, k);
    else cout << Seg::query(1, x, y) % mod << '\n';
  }
  return 0;
}

单调栈

for(int i = 0; i < T.size(); i++){
  while(! stk.empty() && stk.top() > T[i]){
    ?stk.pop();
  }
  stk.push(A[i]);
}

单调队列

上经典的滑动窗口问题

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxn 1000100
using namespace std;
int q[maxn], a[maxn];
int n, k;
void getmin() {
  int head = 0, tail = 0;
  for (int i = 1; i < k; i++) {
    while (head <= tail && a[q[tail]] >= a[i]) tail--;
    q[++tail] = i;
  }
  for (int i = k; i <= n; i++) {
    while (head <= tail && a[q[tail]] >= a[i]) tail--;
    q[++tail] = i;
    while (q[head] <= i - k) head++;
    printf("%d ", a[q[head]]);
  }
}

void getmax() {
  int head = 0, tail = 0;
  for (int i = 1; i < k; i++) {
    while (head <= tail && a[q[tail]] <= a[i]) tail--;
    q[++tail] = i;
  }
  for (int i = k; i <= n; i++) {
    while (head <= tail && a[q[tail]] <= a[i]) tail--;
    q[++tail] = i;
    while (q[head] <= i - k) head++;
    printf("%d ", a[q[head]]);
  }
}

int main() {
  scanf("%d%d", &n, &k);
  for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
  getmin();
  printf("\n");
  getmax();
  printf("\n");
  return 0;
}

树剖

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

int n, m, root, mod, w[A], pre[A];

struct node {
  int to, nxt;
} e[A];

int head[A], cnt;

inline void add_edge(int from, int to) {  
  e[++cnt].to = to;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

namespace Seg {
  struct tree {
    int l, r, w, lazy;
  } t[A]; 
  #define lson rt << 1
  #define rson rt << 1 | 1
  inline void pushup(int rt) {
    t[rt].w = (t[lson].w + t[rson].w) % mod;
  }
  inline void pushdown(int rt) {
    t[lson].lazy += t[rt].lazy, t[rson].lazy += t[rt].lazy; 
    t[lson].lazy %= mod, t[rson].lazy %= mod;
    t[lson].w += (t[lson].r - t[lson].l + 1) * t[rt].lazy; t[lson].w %= mod;
    t[rson].w += (t[rson].r - t[rson].l + 1) * t[rt].lazy; t[lson].w %= mod;
    t[rt].lazy = 0;
  }
  void build(int rt, int l, int r) {
    t[rt].l = l, t[rt].r = r;
    if(l == r) { t[rt].w = w[pre[l]] % mod; return; }
    int mid = (l + r) >> 1;
    build(lson, l, mid); build(rson, mid + 1, r);
    pushup(rt); return;
  }
  void add(int rt, int l, int r, int val) {
    if(l <= t[rt].l && t[rt].r <= r) {
      t[rt].lazy = (t[rt].lazy + val) % mod;
      t[rt].w = (t[rt].w + (t[rt].r - t[rt].l + 1) * val) % mod;
      return;
    }
    if(t[rt].lazy) pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1;
    if(l <= mid) add(lson, l, r, val); 
    if(r > mid) add(rson, l, r, val);
    pushup(rt);
  }
  int asksum(int rt, int l, int r) {
    if(l <= t[rt].l && t[rt].r <= r) {
      return t[rt].w % mod;
    }
    if(t[rt].lazy) pushdown(rt);
    int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
    if(l <= mid) ans += asksum(lson, l, r);
    if(r > mid) ans += asksum(rson, l, r);
    return ans;
  }
}

int dfn[A], son[A], siz[A], dep[A], fa[A], top[A], tot;

void dfs1(int now, int fr) {
  siz[now] = 1, fa[now] = fr, dep[now] = dep[fr] + 1;
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(to == fr) continue; 
    dfs1(to, now);
    siz[now] += siz[to];
    if(siz[to] > siz[son[now]]) son[now] = to;
  }
}

void dfs2(int now, int tp) {
  dfn[now] = ++tot, pre[tot] = now, top[now] = tp; 
  if(son[now]) dfs2(son[now], tp);
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(to == fa[now] || to == son[now]) continue;
    dfs2(to, to);
  }
}

inline void add_qwq(int x, int y, int val) {
  while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) swap(x, y);
    Seg::add(1, dfn[top[x]], dfn[x], val);
    x = fa[top[x]];
  }
  if(dep[x] > dep[y]) swap(x, y);
  Seg::add(1, dfn[x], dfn[y], val);
  return;
}

inline int asksum_qwq(int x, int y) {
  int ans = 0;
  while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) swap(x, y);
    ans += Seg::asksum(1, dfn[top[x]], dfn[x]);
    ans %= mod;
    x = fa[top[x]];
  }
  if(dep[x] > dep[y]) swap(x, y);
  ans += Seg::asksum(1, dfn[x], dfn[y]);
  ans %= mod;
  return ans % mod;
}

int main() {
  n = read(), m = read(), root = read(), mod = read();
  for(int i = 1; i <= n; i++) w[i] = read() % mod;
  for(int i = 1; i < n; i++) {
    int x = read(), y = read();
    add_edge(x, y), add_edge(y, x);
  }
  dfs1(root, 0);
  dfs2(root, root);
  Seg::build(1, 1, n);
  while(m--) { 
    int opt = read(), x, y, z;
    if(opt == 1) x = read(), y = read(), z = read() % mod, add_qwq(x, y, z);
    if(opt == 2) x = read(), y = read(), cout << asksum_qwq(x, y) % mod << '\n';
    if(opt == 3) x = read(), z = read(), Seg::add(1, dfn[x], dfn[x] + siz[x] - 1, z);
    if(opt == 4) x = read(), cout << Seg::asksum(1, dfn[x], dfn[x] + siz[x] - 1) % mod << '\n';
  }
  return 0;
}

求LCA

树剖求LCA

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], son[A], dfn[A], siz[A], fa[A], top[A], tot;

inline void add(int from, int to) {
  e[++cnt].to = to;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

void prepare(int now, int fr) {
  fa[now] = fr, dep[now] = dep[fr] + 1, siz[now] = 1;
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(to == fr) continue;
    prepare(to, now); siz[now] += siz[to];
    if(siz[to] > siz[son[now]]) son[now] = to;
  }
}

void dfs(int now, int tp) {
  top[now] = tp, dfn[now] = ++tot;
  if(son[now]) dfs(son[now], tp);
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(to == fa[now] || to == son[now]) continue;
    dfs(to, to);
  }
}

inline int LCA(int x, int y) {
  while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) swap(x, y);
    x = fa[top[x]];
  }
  if(dep[x] > dep[y]) swap(x, y);
  return x;
}

int main() {
  n = read(), m = read(), R = read();
  for(int i = 1, x, y; i < n; i++) {
    x = read(), y = read();
    add(x, y), add(y, x);
  } 
  prepare(R, 0); dfs(R, R);
  while(m--) {
    int x = read(), y = read();
    cout << LCA(x, y) << '\n';
  }
  return 0;
}

倍增求LCA

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, R;
struct node { int to, nxt; } e[A << 1];
int head[A], cnt, dep[A], fa[A][23], lg[A];

inline void add(int from, int to) {
  e[++cnt].to = to;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

void dfs(int now, int fr) {
  fa[now][0] = fr, dep[now] = dep[fr] + 1;
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(to == fr) continue;
    dfs(to, now);
  }
}

inline int LCA(int x, int y) {
  if(dep[x] < dep[y]) swap(x, y);
  for(int i = 20; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
  if(x == y) return x;
  for(int i = 20; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
  return fa[x][0];
}

int main() {
  n = read(), m = read(), R = read(); lg[1] = 0;
  for(int i = 2, x, y; i <= n; i++) {
    x = read(), y = read();
    add(x, y), add(y, x);
    lg[i] = lg[i >> 1] + 1;
  }
  
  dfs(R, 0); 
  
  for(int j = 1; (1 << j) <= n; j++) 
    for(int i = 1; i <= n; i++)
      fa[i][j] = fa[fa[i][j - 1]][j - 1];
  
  while(m--) {
    int x = read(), y = read();
    cout << LCA(x, y) << '\n';
  }
  
  return 0;
}

ST表

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, a[B], f[B][25], lg[B];

inline int query(int l, int r) {
  int k = lg[r - l + 1];
  return max(f[l][k], f[r - (1 << k) + 1][k]);
}

int main() {
  n = read(), m = read(); lg[0] = -1;
  for(int i = 1; i <= n; i++) a[i] = read(), f[i][0] = a[i], lg[i] = lg[i >> 1] + 1;
  for(int j = 1; (1 << j) <= n; j++) 
    for(int i = 1; i <= n; i++)
      f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
  while(m--) {
    int x = read(), y = read();
    cout << query(x, y) << '\n';
  }
  return 0;
}

数学/数论

求逆元

递推1~n的逆元

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;

const int A = 1e5 + 11;
const int B = 3e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, p;
ll inv[B];

int main() {
  n = read(), p = read();
  inv[1] = 1;
  for(int i = 2; i <= n; i++) {
    inv[i] = 1LL * (p - p / i) * inv[p % i] % p;
  }
  for(int i = 1; i <= n; i++) cout << inv[i] << '\n';
  return 0;
}

矩阵快速幂

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e2 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x =  + (c ^ 48);
  return x * f;
}

int n, k;
struct matrix {
  int a[A][A];
  matrix() { memset(a, 0, sizeof(a)); }
  void init() { for(int i = 1; i <= n; i++) a[i][i] = 1; }
} ans, a;

matrix operator * (const matrix &x, const matrix &y) {
  matrix qwq;
  for(int k = 1; k <= n; k++) 
    for(int i = 1; i <= n; i++) 
      for(int j = 1; j <= n; j++)
        qwq.a[i][j] = (qwq.a[i][j] + x.a[i][k] * y.a[k][j] % mod) % mod;
  return qwq; 
}

inline void power() {
  while(k) {
    if(k & 1) ans = ans * a;
    a = a * a; k >>= 1;
  }
}

signed main() {
  n = read(), k = read();
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++) 
      a.a[i][j] = read();
  ans.init();
  power();
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= n; j++) {
      cout << ans.a[i][j] << " ";
    }
    puts("");
  }
  return 0;
}

快速乘

//知识点:快速乘
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

int a, b, p, ans;

int mul(int a, int b, int mod) {
  int res = 0;
  while(b) {
    if(b & 1) res = (res + a) % mod;
    a = (a + a) % mod;
    b >>= 1;
  }
  return res % mod;
}

signed main() {
  a = read(), b = read(), p = read();
  ans = mul(a, b, p);
  cout << ans << '\n';
  return 0;
}

快速幂

//知识点:快速幂 
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

int a, b, p, ans;

int power(int a, int b, int mod) {
  int res = 1;
  while(b) {
    if(b & 1) res = res * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return res % mod;
}

signed main() {
  a = read(), b = read(), p = read();
  ans = power(a, b, p);
  cout << ans << '\n';
  return 0;
}

埃氏筛

void prime(int n) {
  cnt = 0;
  vis[0] = vis[1] = 1;
  for(int i = 2; i <= n; ++i) {
    if(!vis[i]) {
      p[++cnt] = i;
      for(int j = i * i; j <= n; j+=i) {
        vis[j] = true;
      }
    }
  }
}

线性筛

int vis[N], p[N], cnt;

void prepare() {
  vis[0] = vis[1] = 1;
  for(int i = 2; i <= n; i++) {
    if(!vis[i]) p[++cnt] = i;
    for(int j = 1; j <= cnt; j++) {
      if(i * p[j] > n) break;
      vis[i * p[j]] = 1;
      if(i % p[j] == 0) break;
    }
  }
}

动态规划

最长上升子序列

普通二分

//知识点:
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 10001;

int f[N], a[N], n;
int len = 1;

int main() {
  memset(f, 0x3f, sizeof(f));
  n = read();
  for(int i = 1; i <= n; i++) a[i] = read();
  f[len] = a[1];
  for(int i = 2; i <= n; i++) {
    int l = 1, r = len, mid, rec;
    if(a[i] > f[len]) f[++len] = a[i];
    else {
      while(l <= r) {
        mid = (l + r) / 2;
        if(f[mid] >= a[i]) rec = mid, r = mid - 1;
        else l = mid + 1;
      }
      f[rec] = min(f[rec], a[i]);
    }
  }
  for(int i = 1; i <= len; i++) cout << f[i] << " ";
  cout << '\n' << len << '\n'; 
  return 0;
}
/*
9
7 2 1 5 6 4 3 8 9
*/

lower_bound

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 10001;

int f[N], a[N], n;
int len = 1;

int main() {
  memset(f, 0x3f, sizeof(f));
  n = read();
  for(int i = 1; i <= n; i++) a[i] = read();
  f[1] = a[1];
  for(int i = 2; i <= n; i++) {
    if(a[i] > f[len]) f[++len] = a[i];
    else { 
      int p = lower_bound(f + 1, f + len + 1 , a[i]) - f;
      f[p] = a[i];
    }
  }
  for(int i = 1; i <= len; i++) cout << f[i] << " ";
  cout << '\n' << len << '\n';
  return 0;
}

最长公共子序列

\(n^2\)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 1011;

int dp[N][N], a1[N], a2[N], n, m;

int main() {
  n = read();
  for(int i = 1; i <= n; i++) a1[i] = read();
  for(int i = 1; i <= n; i++) a2[i] = read();
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= n; j++) {
      dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
      if(a1[i] == a2[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
    }
  cout << dp[n][n] << '\n';
  return 0;
}

图论

tarjan

#include <bits/stdc++.h>
using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    return x * f;
}

const int N = 1011;

struct node {
    int to, nxt;
} e[N];

int low[N], dfn[N], tot, topp = 0, sta[N], cnt, head[N];
bool vis[N];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].nxt = head[from];
    head[from] = tot;
}

void tarjan(int u) {
    dfn[u] = low[u] = ++cnt, sta[++topp] = u, vis[u] = 1;
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]) {
        do {
            cout << sta[topp] << ' ';
            vis[sta[topp--]] = 0;
        }while(u != sta[topp + 1]);
        cout << '\n';
    }
}

int n, m;

int main() {
    n = read(), m = read();
    for(int i = 1; i <= m; i++) {
        int u = read(), v = read();
        add(u, v);
    }
    for(int i = 1; i <= n; i++) 
        if(!dfn[i]) tarjan(i);
}
/*
5 8
1 2
2 3
3 6
5 6
1 4
4 5
5 1
2 5
*/

最小生成树

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 2e5 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

int n, m, fa[A], cnt, ans;
struct node { int x, y, val; } e[A];
int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
bool cmp(node x, node y) { return x.val < y.val; }

int main() {
  n = read(), m = read();
  for(int i = 1; i <= n; i++) fa[i] = i;
  for(int i = 1; i <= m; i++) e[i].x = read(), e[i].y = read(), e[i].val = read();
  sort(e + 1, e + 1 + m, cmp);
  for(int i = 1; i <= m; i++) {
    int dx = find(e[i].x), dy = find(e[i].y);
    if(dx != dy) {
      fa[dy] = dx;
      ans += e[i].val;
      cnt++;
      if(cnt == n - 1) break;
    }
  }
  cout << ans << '\n';
  return 0;
}

求树的直径

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

const int M = 3e5 + 11;

int n, cnt, k, ans, head[M], dep[M], vis[M];

struct node {
    int nxt, to;
} edge[M];

void add(int from, int to) {
    edge[++cnt].nxt = head[from];
    edge[cnt].to = to;
    head[from] = cnt;
}

void dfs(int x, int fx) {
    vis[x] = 1;
    for(int i = head[x]; i; i = edge[i].nxt) {
        int to = edge[i].to;
        if(to == fx) continue;
        dep[to] = dep[x] + 1;
        if(ans < dep[to]) {
            ans = dep[to];
            k = to;
        }
        dfs(to, x);
    }
}

int main() {
    n = read();
    for(int i = 1; i < n; i++) {
        int x = read(), y = read();
        add(x, y), add(y, x);
        ans = 0, dep[x] = 0, memset(vis, 0, sizeof(vis)); dfs(x, 0);
        ans = 0, dep[k] = 0, memset(vis, 0, sizeof(vis)); dfs(k, 0);
        cout << ans << '\n';
    }
    return 0;
}

二分图匹配

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, E, ans;
struct node { int to, nxt; } e[A];
int head[A], cnt, match[A], vis[A];

inline void add(int from, int to) {
  e[++cnt].to = to;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

bool dfs(int now) {
  for(int i = head[now]; i; i = e[i].nxt) {
    int to = e[i].to;
    if(vis[to]) continue;
    vis[to] = 1;
    if(!match[to] || dfs(match[to])) {
      match[to] = now;
      return 1;
    }
  }
  return 0;
} 

int main() {
  n = read(), m = read(), E = read();
  for(int i = 1, x, y; i <= E; i++) {
    x = read(), y = read();
    if(x > n || y > m) continue;
    add(x, y);
  }
  for(int i = 1; i <= n; i++) {
    memset(vis, 0, sizeof(vis));
    if(dfs(i)) ans++;
  }
  cout << ans << '\n';
  return 0;
}

最短路

堆优化dij

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, dis[A], S;
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
  e[++cnt].to = to;
  e[cnt].val = val;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

struct edge {
  int x, y;
  bool operator < (const edge &qwq) const {
    return y > qwq.y;
  }
};

priority_queue<edge> Q;
inline void ZDL() {
  memset(dis, inf, sizeof(dis));
  dis[S] = 0;
  Q.push((edge) {S, 0});
  while(!Q.empty()) {
    int u = Q.top().x, d = Q.top().y; Q.pop();
    if(d != dis[u]) continue;
    for(int i = head[u]; i; i = e[i].nxt) {
      int to = e[i].to;
      if(dis[to] > dis[u] + e[i].val) {
        dis[to] = dis[u] + e[i].val;
        Q.push((edge) {to, dis[to]});
      }
    }
  }
}

int main() {
//  freopen("testdata.in", "r", stdin);
  n = read(), m = read(), S = read();  
  for(int i = 1, x, y, val; i <= m; i++) {
    x = read(), y = read(), val = read();
    add(x, y, val);
  }
  ZDL();
  for(int i = 1; i <= n; i++) {
    if(dis[i] == inf) cout << "2147483647 ";
    else cout << dis[i] << " ";
  }
  return 0;
}

SPFA

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, dis[A], S, vis[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
  e[++cnt].to = to;
  e[cnt].val = val;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

queue <int> Q;
inline void SPFA() {
  memset(dis, inf, sizeof(dis));
  dis[S] = 0, vis[S] = 1;
  Q.push(S);
  while(!Q.empty()) {
    int u = Q.front(); Q.pop(); vis[u] = 0;
    for(int i = head[u]; i; i = e[i].nxt) {
      int to = e[i].to;
      if(dis[to] > dis[u] + e[i].val) {
        dis[to] = dis[u] + e[i].val;
        if(!vis[to]) {
          vis[to] = 1;
          Q.push(to);
        }
      }
    }
  }
}

signed main() {
  n = read(), m = read(), S = read();  
  for(int i = 1, x, y, val; i <= m; i++) {
    x = read(), y = read(), val = read();
    add(x, y, val);
  }
  SPFA();
  for(int i = 1; i <= n; i++) cout << dis[i] << " ";
  return 0;
}

判负环

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, dis[A], S = 1, vis[A], tot[A];
struct node { int to, nxt, val; } e[B];
int head[A], cnt;

inline void add(int from, int to, int val) {
  e[++cnt].to = to;
  e[cnt].val = val;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

inline bool SPFA() {
  memset(dis, inf, sizeof(dis));
  dis[S] = 0, vis[S] = 1, tot[S] = 1;
  queue <int> Q;
  Q.push(S);
  while(!Q.empty()) {
    int u = Q.front(); Q.pop(); vis[u] = 0;
    for(int i = head[u]; i; i = e[i].nxt) {
      int to = e[i].to;
      if(dis[to] > dis[u] + e[i].val) {
        if(++tot[to] >= n) return 1;
        dis[to] = dis[u] + e[i].val;
        if(!vis[to]) {
          vis[to] = 1;
          Q.push(to);
        }
      }
    }
  }
  return 0;
}

signed main() {
  int T = read();
  while(T--) {
    memset(head, 0, sizeof(head));  
    memset(vis, 0, sizeof(vis));
    memset(tot, 0, sizeof(tot));
    n = read(), m = read();
    for(int i = 1, x, y, val; i <= m; i++) {
      x = read(), y = read(), val = read();
      add(x, y, val);
      if(val >= 0) add(y, x, val);
    }
    if(SPFA()) puts("YE5");
    else puts("N0");
  }
  return 0;
}

字符串

\(hash\)

/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define ull unsigned long long
using namespace std;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
  return x * f;
}

const int N = 211;

char pa[N][N], meng[N];
int n, m, a[N], l[N], ans, cnt[N];
ull p[N], cnm[N][N], sjp[N];


bool query(int l1, int r1,int now) {
  ull h1, h2;
  h1 = sjp[r1] - sjp[l1 - 1] * p[r1 - l1 + 1];
  h2 = cnm[now][l[now]];
  return h1 == h2;
}

void work2() {//cnm
  memset(sjp, 0, sizeof(sjp));
  int len = strlen(meng + 1);
  for(int i = 1; i <= len; i++) {
    sjp[i] = sjp[i - 1] * 27 + meng[i] - 'a' + 1;
  }
  for(int i = 1; i <= m; i++) {
    for(int j = 1; j <= len; j++) {
      if(meng[j] == pa[i][1]) {
        if(query(j, j + l[i] - 1, i)) ans += j * a[i];
      }
    }
  }
}

int main() {
  freopen("dream.in", "r", stdin);
  freopen("dream.out", "w", stdout);
  n = read(), m = read();
  p[0] = 1;
  for(int i = 1; i <= 200; i++) p[i] = p[i - 1] * 27ull;
  for(int i = 1; i <= m; i++) scanf("%s", pa[i] + 1), l[i] = strlen(pa[i] + 1);
  for(int i = 1; i <= m; i++)
    for(int j = 1; j <= l[i]; j++)
      cnm[i][j] = cnm[i][j - 1] * 27 + pa[i][j] - 'a' + 1;
  for(int i = 1; i <= m; i++) a[i] = read();
  for(int i = 1; i <= n; i++) scanf("%s", meng + 1), work2();
  cout << ans << '\n';
  return 0;
}

KMP

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
  for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n, m, nxt[A];
char s[A], t[A];

void get_nxt() {
  int p = 0;
  for(int i = 2; i <= m; i++) {
    while(p && t[i] != t[p + 1]) p = nxt[p];
    if(t[i] == t[p + 1]) ++p;
    nxt[i] = p;
  }
}

int main() {
  scanf("%s", s + 1); scanf("%s", t + 1);
  n = strlen(s + 1), m = strlen(t + 1);
  get_nxt();
  int p = 0;
  for(int i = 1; i <= n; i++) {
    while(p && s[i] != t[p + 1]) p = nxt[p];
    if(s[i] == t[p + 1]) {
      ++p;
      if(p == m) {
        cout << i - m + 1 << '\n';
        p = nxt[p];
      }
    }
  }
  for(int i = 1; i <= m; i++) cout << nxt[i] << " ";
  return 0;
}
posted @ 2019-10-07 19:34  Loceaner  阅读(572)  评论(11编辑  收藏  举报