简单模板

并查集

int ht[N];
int fa[N];
int n;  // point numers
void init_set() {
    for (int i = 1; i <= n; ++i) fa[i] = i, ht[i] = 0;
}
int Find(int x) {
    if (x != fa[x]) fa[x] = Find(fa[x]);  //路径压缩
    return fa[x];
}
int find_set_circle(int x) {
    int r = x;
    while (fa[r] != r) r = fa[r];  //找到根节点
    for (int i = x, j; i != r; i = j)
        j = fa[i], fa[i] = r;  //把路径上的元素的集改为根节点
    return r;
}
void union_set(int x, int y) {
    x = Find(x);
    y = Find(y);
    if (ht[x] == ht[y])
        ht[x] = ht[x] + 1, fa[y] = x;
    else if (ht[x] < ht[y])
        fa[x] = y;
    else
        fa[y] = x;
}

管理节点数量,无按秩归并

//hdu1856

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10000005;
int sum[maxn];      //集合总数
int ufs[maxn];      //父节点
void Init(int n) {  //初始化
    for (int i = 1; i <= n; i++) {
        ufs[i] = i;
        sum[i] = 1;
    }
}
int Find(int a) {       //获得a的根节点。路径压缩
    if (ufs[a] != a) {  //没找到根节点
        int tmp = ufs[a];
        ufs[a] = Find(ufs[a]);
    }
    return ufs[a];
}
void Merge(int a, int b) {  //合并a和b的集合
    int x = Find(a);
    int y = Find(b);
    if (x != y) {
        ufs[x] = y;
        sum[y] += sum[x];
    }
}
int main() {
    int t, a, b;
    while (~scanf("%d", &t)) {
        Init(maxn);
        while (t--) {
            scanf("%d%d", &a, &b);
            Merge(a, b);
        }
        int ans = -1;
        for (int i = 1; i <= maxn; ++i) ans = max(ans, sum[i]);
        printf("%d\n",ans);
    }
    return 0;
}

食物链(关系并查集)

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 50010;
struct node {
    int pre;       //父节点
    int relation;  //与父节点之间的关系
} p[N];
/*
在这里,向量指的是“偏移量”,表示的是子节点与父节点之间的关系。
0表示与父节点属于同一种族;
1表示被父节点吃;
2表示吃父节点。
*/
int find(int x) {  //查找根结点
    int temp;
    if (x == p[x].pre) return x;
    temp = p[x].pre;  //路径压缩
    p[x].pre = find(temp);
    p[x].relation = (p[x].relation + p[temp].relation) % 3;  //关系域更新
    return p[x].pre;  //根结点
}
int main() {
    int n, k;
    int sum = 0;  //假话数量
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) {  //初始化
        p[i].pre = i;
        p[i].relation = 0;
    }
    int ope, a, b;
    for (int i = 1; i <= k; ++i) {
        scanf("%d%d%d", &ope, &a, &b);
        if (a > n || b > n || ope == 2 && a == b) sum++;
        else {
            int root1 = find(a);
            int root2 = find(b);
            if (root1 != root2) {  // 合并
                p[root2].pre = root1;
                // 此时 rootx->rooty = rootx->x + x->y + y->rooty
                p[root2].relation = (3 + p[a].relation + (ope - 1) - p[b].relation) % 3;
            } else {
                //验证x->y之间的偏移量是否与题中给出的d-1一致
                if (ope == 1 && p[a].relation != p[b].relation) sum++;
                else if (ope == 2 && (3 - p[a].relation + p[b].relation) % 3 != ope - 1)
                    sum++;
            }
        }
    }
    printf("%d\n", sum);
    return 0;
}

KMP

//模板
void GetNextval(string p, int next[]) {
    int pLen = p.length()-1;
    next[0] = -1;
    for (int i = 0, j = -1; i < pLen;) {
        if (j == -1 || p[i] == p[j]) {
            if (p[++i] != p[++j]) next[i] = j;
            else next[i] = next[j];
        } else j = next[j];
    }
}

区间DP

题意

n个点在数轴上排列,从其中一个点出发。每个点都有要求的最晚到达时间,问能否全部准时到达,如果能,给出完成时间。

分析

题目给出的n个景点是按照位置信息升序排列的。

把起始点,即t为0的点设为k,所有的点分成了两部分:k点左边的点和k点右边的点。

我们用一个数组dp[i][j][f]表示完成左边i个点右边j个点的最少所需时间,f==0时表示在左边结束,f==1时表示在右边结束。

看着数轴,考虑在左边结束的情况,即dp[i][j][0]:

  1. 上一个落脚点是左边(从右往左数,下同)第i-1个点,那么就是dp[i-1][j][0]再加上两点之间所需要消耗的时间即可。
  2. 上一个落脚点是右边第j个点.

所以

同理

然后逐个比对,遇到不符合的情况直接退出即可。

solution

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e3 + 5;
int dp[N][N][2];
int d[N], t[N];
int main() {
    int n,k;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> d[i];
    for (int i = 1; i <= n; i++) cin >> t[i];
    for (int i = 1; i <= n; i++) if (t[i] == 0) k = i;
    fill(**dp, **dp+sizeof(dp)/4, INF);
    dp[0][0][1] = dp[0][0][0] = 0;
    for (int i = 0; i <= k - 1; i++) 
        for (int j = 0; j <= n - k; j++) {
            if (i) dp[i][j][0] = min(dp[i - 1][j][0] - d[k - i] + d[k - i + 1], dp[i - 1][j][1] + d[j + k] - d[k - i]);
            if (j) dp[i][j][1] = min(dp[i][j - 1][1] + d[j + k] - d[j - 1 + k], dp[i][j - 1][0] + d[j + k] - d[k - i]);
            if (dp[i][j][0] > t[k - i] && dp[i][j][1] > t[j + k]) { cout << -1; return 0; }
            if (dp[i][j][0] > t[k - i]) dp[i][j][0] = INF;
            if (dp[i][j][1] > t[k + j]) dp[i][j][1] = INF;
        }
    cout << min(dp[k - 1][n - k][0], dp[k - 1][n - k][1]);
    return 0;
}

杜教筛

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define pb push_back
typedef long long ll;
#define SZ(x) ((ll)(x).size())
typedef vector<ll> VI;
typedef pair<ll, ll> PII;
const ll mod = 998244353;
ll powmod(ll a, ll b) { ll res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1)res = res * a % mod; a = a * a % mod; }return res; }
// head

ll _, n;
namespace linear_seq {
    const ll N = 10010;
    ll res[N], base[N], _c[N], _md[N];

    vector<ll> Md;
    void mul(ll* a, ll* b, ll k) {
        rep(i, 0, k + k) _c[i] = 0;
        rep(i, 0, k) if (a[i]) rep(j, 0, k) _c[i + j] = (_c[i + j] + a[i] * b[j]) % mod;
        for (ll i = k + k - 1; i >= k; i--) if (_c[i])
            rep(j, 0, SZ(Md)) _c[i - k + Md[j]] = (_c[i - k + Md[j]] - _c[i] * _md[Md[j]]) % mod;
        rep(i, 0, k) a[i] = _c[i];
    }
    ll solve(ll n, VI a, VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
//        printf("%d\n",SZ(b));
        ll ans = 0, pnt = 0;
        ll k = SZ(a);
        assert(SZ(a) == SZ(b));
        rep(i, 0, k) _md[k - 1 - i] = -a[i]; _md[k] = 1;
        Md.clear();
        rep(i, 0, k) if (_md[i] != 0) Md.push_back(i);
        rep(i, 0, k) res[i] = base[i] = 0;
        res[0] = 1;
        while ((1ll << pnt) <= n) pnt++;
        for (ll p = pnt; p >= 0; p--) {
            mul(res, res, k);
            if ((n >> p) & 1) {
                for (ll i = k - 1; i >= 0; i--) res[i + 1] = res[i]; res[0] = 0;
                rep(j, 0, SZ(Md)) res[Md[j]] = (res[Md[j]] - res[k] * _md[Md[j]]) % mod;
            }
        }
        rep(i, 0, k) ans = (ans + res[i] * b[i]) % mod;
        if (ans < 0) ans += mod;
        return ans;
    }
    VI BM(VI s) {
        VI C(1, 1), B(1, 1);
        ll L = 0, m = 1, b = 1;
        rep(n, 0, SZ(s)) {
            ll d = 0;
            rep(i, 0, L + 1) d = (d + (ll)C[i] * s[n - i]) % mod;
            if (d == 0) ++m;
            else if (2 * L <= n) {
                VI T = C;
                ll c = mod - d * powmod(b, mod - 2) % mod;
                while (SZ(C) < SZ(B) + m) C.pb(0);
                rep(i, 0, SZ(B)) C[i + m] = (C[i + m] + c * B[i]) % mod;
                L = n + 1 - L; B = T; b = d; m = 1;
            }
            else {
                ll c = mod - d * powmod(b, mod - 2) % mod;
                while (SZ(C) < SZ(B) + m) C.pb(0);
                rep(i, 0, SZ(B)) C[i + m] = (C[i + m] + c * B[i]) % mod;
                ++m;
            }
        }
        return C;
    }
    ll gao(VI a, ll n) {
        VI c = BM(a);
        c.erase(c.begin());
        rep(i, 0, SZ(c)) c[i] = (mod - c[i]) % mod;
        return solve(n, c, VI(a.begin(), a.begin() + SZ(c)));
    }
};

inline ll read() {
    ll s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

ll f[10005];

int main() {
    ll n = read(), k = read();
    f[1] = 1, f[2] = 1;
    for (int i = 3; i <= 10000; ++i)
        f[i] = (f[i - 1] + f[i - 2]) % mod;
    VI a;
    ll x = 0;
    for (int i = 1; i <= 10000; ++i) {
        x = (x + powmod(i, k) * f[i] % mod) % mod;
        a.push_back(x);
    }
    printf("%lld\n", linear_seq::gao(a, n - 1));
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务