考前複習

前言

由於loceaner太菜了,他什麼東西都不會
因此他打算學一個東西就記錄一下
不過由於他很菜,因此他不會寫原理……
並且,他但願在2019CSP以前不會斷更
就醬紫,就是寫給他本身的……由於他太菜了node

別犯些傻逼錯誤好很差啊!你丟多少分了!

基礎算法

小技巧

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

使用負數下標

如何使用負數下標呢?
讓數組前面有東西c++

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

這樣的話調用\(z[-50]\)就變成了調用\(y[0]\)git

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;
}

二維差分

//知識點:
/*
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]+...\)
即:逆序和 <= 亂序和 <= 正序和ui

關於\(long\ long\)

在平常的題目中,必定要看好數據範圍,若是會爆\(int\)的話,不要忘記開\(long long\)(無數次被坑!!)this

高精度模板

最讓人煩的就是高精度了,某些題並不難,可是要寫高精。。煩\(\color{white}{(ps:板子來自lfd)}\)spa

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;

數據結構

單調棧

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;
}

\(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;
}

數學/數論

快速乘

//知識點:快速乘
/*
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
*/
相關文章
相關標籤/搜索