NOIPのテンプレートまとめ

33111 ワード

このブログはまだ完全に書き終わっていないので、後で更新しますが、いつになったのか分かりません.しかし、小さな貢献をして、皆さんに役に立つことを望んでいます.

数論


GCD

LL gcd(LL a, LL b) { return !b ? a : gcd(b, a%b); }

EXGCD

// gcd(a, b) = a*x+b*y;
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if(!b) { x = 1; y = 0; return a; }
    LL x0, y0, d = exgcd(b, a%b, x0, y0);
    x = y0; y = x0-(a/b)*y0;
    return d;
}

LUCAS

// C(n,m) =  C(n/p, m/p)*C(n%p, m%p) (mod p) (when 0 <= m <= n)
// C(n,m) = 0 (mod p)   (when m > n)
LL lucas(LL n, LL m, LL MOD) {
    if(m > n) return 0;
    if(n < MOD) return comb(n, m, MOD);
    return lucas(n/MOD, m/MOD, MOD)*comb(n%MOD, m%MOD, MOD)%MOD;
}

拡張LUCAS


ぎゃくげん

// a^-1
LL inv(LL a, LL MOD) {
    LL x,y;
    exgcd(a, MOD, x, y);
    return (x%MOD+MOD)%MOD;
} 

    vfac[0] = vfac[1] = 1;
    for(int i = 2; i <= maxn; i++) vfac[i] = (MOD-MOD/i)*vfac[MOD%i]%MOD;

CRT

// x = a (mod m)
LL crt(LL *va, LL *vm, int n) {
    LL sum = 1, ans = 0;
    for(int t = 0; t < n; t++) sum *= vm[t];
    for(int t = 0; t < n; t++) {
        LL mi = sum/vm[t], vmi = inv(mi, vm[t]);
        ans += mi*vmi%sum*va[t]%sum;
        if(ans >= sum) ans -= sum;
    }
    return ans;
}

拡張CRT


配列の組合せ


カトラン数

inline LL catalan(LL N, LL MOD) { return comb(2*N, N, MOD)/(N+1); }

まちぎょうれつ

// D(1) = 0, D(2) = 1
// D(n) = (n-1)*(D(n-1)+D(n+2))
LL D[maxn];
void cuopai(int N, int MOD) {
    D[1] = 0, D[2] = 1;
    for(int i = 3; i <= N; i++) D[i] = (i-1)*(D[i-1]+D[i-2])%MOD;
}

スターリングすう


高速べき乗

inline LL powermod(LL a, LL b, LL MOD) {
    LL ans = 1; a %= MOD;
    while(b) {
        if(b&1) ans = ans*a%MOD, b--;
        b >>= 1; a = a*a%MOD;
    }
    return ans%MOD;
}

マトリックス高速べき乗


ふるいほう

//  
int pri[maxn]; 
void checkprime(int N) {
    pri[1] = 1;
    for(int i = 2; i <= sqrt(N); i++) if(!pri[i])
        for(int j = 2; j*i <= N; j++) pri[i*j] = 1;
} 

せんけいふるい

//  
bool isprime[maxn];
int prime[maxn],mu[maxn],phi[maxn],tao[maxn],d[maxn],cnt_pri;
void linear_sieve(int N) {
    isprime[1] = mu[1] = phi[1] = tao[1] = 1; d[1] = 0;
    for(int i = 2; i <= N; i++) {
        if(!isprime[i]) prime[++cnt_pri] = i, mu[i] = -1, phi[i] = i-1, tao[i] = 2, d[i] = 1;
        for(int t = 0; t < cnt_pri; t++) {
            int j = prime[t]*i;
            if(j > N) break;
            isprime[j] = 1;
            mu[j] = mu[prime[t]]*mu[i];
            phi[j] = phi[prime[t]]*phi[i];
            tao[j] = tao[i]<<1;
            d[j] = 1;
            if(!(i%prime[t])) { mu[j] = 0; phi[j] = prime[t]*phi[i]; tao[j] = tao[i]/(d[i]+1)*(d[i]+2); d[j] = d[i]+1; break; }
        }
    }
}

ガウス消元


リニアベース


図論


さいたんらく


floyd


dijkstra


SPFA


さぶんこうそくシステム


最短パスツリー


二分図


ハンガリー


にぶんずせんしょく


find union set


パス圧縮

#include 

const int maxn = 1e6+5;
int n,fa[maxn],siz[maxn];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void unionn(int x, int y) {
    int fx = find(x), fy = find(y);
    if(fx == fy) return ;
    fa[fx] = fy;
}//naive

int main () {
    for(int i = 1; i <= n; i++) fa[i] = i;
    return 0;
} 

ランク別集計

#include 
#include 
#include 

const int N = 500005;

template <class T> inline void read(T &x) {
    int flag = 1; x = 0;
    char ch = (char)getchar();
    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = (char)getchar(); }
    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = (char)getchar(); }
    x *= flag;
}

int n,m,fa[N],rank[N],tim,w[N],dep[N];

int Merge(int u, int v) {
    if(rank[u] > rank[v]) fa[v] = u, w[v] = tim;
    else {
        fa[u] = v; w[u] = tim;
        if(rank[u] == rank[v]) rank[v]++;
    }
}

int Find(int x) { return fa[x] == x ? x : Find(fa[x]); }

void Dfs(int u) {
    if(fa[u] == u) return;
    Dfs(fa[u]);
    dep[u] = dep[fa[u]] + 1;
}

int Query(int u, int v) {
    int ans = 0;
    Dfs(u), Dfs(v);
    if(dep[u] < dep[v]) std :: swap(u, v);
    while(dep[u] > dep[v] && u != v) ans = std :: max(ans, w[u]), u = fa[u];
    while(u != v) ans = std :: max(std :: max(ans, w[u]), w[v]), u = fa[u], v = fa[v];
    return ans;
}

int main() {
    read(n), read(m);
    for(int i = 1; i <= n; i++) fa[i] = i;
    int lsa = 0, opt, a, b;
    for(int i = 1; i <= m; i++) {
        read(opt), read(a), read(b);
        a ^= lsa, b ^= lsa;
        int tp1 = Find(a), tp2 = Find(b);
        if(!opt) {
            tim++;
            if(tp1 != tp2) Merge(tp1, tp2);
        }
        else 
            if(tp1 != tp2) printf("0
"
), lsa = 0; else lsa = Query(a, b), printf("%d
"
,lsa); } return 0; }

オーラかいろ


Tarjan


カットポイント

void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idc;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].v;
        if(v == fa) continue;
        if(!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]) iscut[u]++;
        } else low[u] = min(low[u], dfn[v]);
    }
}

ブリッジエッジ

void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idc;
    int times = 0;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].v;
        if(!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u]) bridge[++bridgecnt] = i;
        } else if(v == fa) {
            if(times) low[u] = min(low[u], dfn[v]);
            times++;
        } else low[u] = min(low[u], dfn[v]);
    }
}

しゅくてん

#include 
#include 

using namespace std;

int n,m,d,cnt,scc,ind,top;
int v[105],w[105],sv[105],sw[105];
int dfn[105],low[105],blg[105];
int q[105],f[105][505],in[505];
struct edge { int to,nxt; } e[505],ed[505];
int lst[105],lst2[105];
bool inq[105];

template  inline void read(T &x) {
    int flag = 1; x = 0;
    char ch = (char)getchar();
    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = (char)getchar(); }
    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = (char)getchar(); }
    x *= flag;
}

inline void add(int u, int v) { e[++cnt].to = v; e[cnt].nxt = lst[u]; lst[u] = cnt; }

inline void ins(int u, int v) { in[v] = 1; ed[++cnt].to = v; ed[cnt].nxt = lst2[u]; lst2[u] = cnt; }

void tarjan(int x) {
    int now = 0;
    low[x] = dfn[x] = ++ind;
    q[++top] = x; inq[x] = 1;
    for(int i = lst[x]; i; i = e[i].nxt)
        if(!dfn[e[i].to]) tarjan(e[i].to), low[x] = min(low[x], low[e[i].to]); 
        else if(inq[e[i].to]) low[x] = min(low[x], dfn[e[i].to]);
    if(low[x] == dfn[x]) {
        scc++;
        while(now != x) {
            inq[now = q[top--]] = 0;
            blg[now] = scc;
            sv[scc] += v[now];
            sw[scc] += w[now];
        }
    }
}

void dp(int x) {
    for(int i = lst2[x]; i; i = ed[i].nxt) {
        dp(ed[i].to);
        for(int j = m-sw[x]; j >= 0; j--)
            for(int k = 0; k <= j; k++) f[x][j] = max(f[x][j], f[x][k]+f[ed[i].to][j-k]);
    }
    for(int j = m; j >= 0; j--) f[x][j] = j >= sw[x] ? f[x][j-sw[x]]+sv[x] : 0;
}

int main() {
    read(n); read(m);
    for(int i = 1; i <= n; i++) read(w[i]);
    for(int i = 1; i <= n; i++) read(v[i]);
    for(int i = 1; i <= n; i++) { read(d); if(d) add(d, i); }
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    cnt = 0;
    for(int x = 1; x <= n; x++)
        for(int i = lst[x]; i; i = e[i].nxt)
            if(blg[e[i].to] != blg[x]) ins(blg[x], blg[e[i].to]);
    for(int i = 1; i <= scc; i++) if(!in[i]) ins(scc+1, i);
    dp(scc+1);
    printf("%d
"
,f[scc+1][m]); return 0; }

MST

#include
#include
#include
#include

using namespace std;

const int maxn = 305;
int n,x,tot,ans;
int fa[maxn];
struct edge {
    int u,v,val;
    bool operator < (const edge &a) const { return val < a.val; }
} e[maxn*maxn];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

inline void unionn(int a, int b) { fa[find(a)] = find(b); }

int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) scanf("%d",&x), e[++tot].u = 0, e[tot].v = i, e[tot].val = x, fa[i] = i;
    for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++)
        scanf("%d",&x), e[++tot].u = i, e[tot].v = j, e[tot].val = x;
    sort(e+1, e+1+tot);
    for(int i = 1; i <= tot; i++) if(find(e[i].u) != find(e[i].v)) ans += e[i].val, unionn(e[i].u, e[i].v);
    printf("%d",ans);
    return 0;
}

トポロジのソート


ツリーチェーン分割


ツリー


重心


ちょつけい


dfsシーケンス


LCA


ばいりつ


定数クエリー


データ構造


はいれつ


チェーンテーブル


キュー


ゆうげんキュー


STテーブル


スタック


手書きの山


STL


左偏樹

#include 
#include 
#include 
#define clr(x) memset(x, 0, sizeof x)
#define digit (ch <  '0' || ch >  '9')

using namespace std;

template <class T> inline void read(T &x) {
    int flag = 1; x = 0;
    register char ch = getchar();
    while( digit) { if(ch == '-')  flag = -1; ch = getchar(); }
    while(!digit) { x = (x<<1)+(x<<3)+ch-'0'; ch = getchar(); }
    x *= flag;
}

const int N = 100005;
int n, m;
int rs[N],ls[N],fa[N],dis[N],str[N];

int merge(int x, int y) {
    if(!x || !y) return x+y;
    if(str[x] < str[y]) swap(x, y);
    rs[x] = merge(rs[x], y);
    if(dis[rs[x]] > dis[ls[x]]) swap(ls[x], rs[x]);
    dis[x] = dis[rs[x]]+1;
    fa[ls[x]] = fa[rs[x]] = fa[x] = x;
    return x; 
}

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

int main() {
    while(~scanf("%d",&n)) {
        clr(ls), clr(rs), clr(dis);
        dis[0] = -1;
        for(int i = 1; i <= n; i++) read(str[i]), fa[i] = i;
        read(m);
        int x,y;
        while(m--) {
            read(x), read(y);
            int fx = find(x), fy = find(y);
            if(fx == fy) printf( "-1
"
); else { str[fx] >>= 1; str[fy] >>= 1; int hp1 = merge(ls[fx], rs[fx]); int hp2 = merge(ls[fy], rs[fy]); ls[fx] = rs[fx] = dis[fx] = 0; ls[fy] = rs[fy] = dis[fy] = 0; fx = merge(fx, hp1); fy = merge(fy, hp2); int ans = merge(fx, fy); printf( "%d
"
, str[ans] ); } } } return 0; }

ツリー配列


セグメントツリー


莫隊


ブロックぶんかつ


CDQ分治


へいこうじゅ


検索


DFS


BFS


IDDFS


A*


Alpha-Beta


枝を切る


さいてきせんだん


実行可能性のある枝切り


分岐境界


文字列


KMP


Trie


manacher


hash


DP


デジタルDP


状圧DP


区間DP


リュックサック


01


完全


ぶぶん


ツリーDP


期待DP



読み込み最適化


チェーンフォワードスター


さぶん


接頭辞和


りさんか


ビット演算


hash


高精度