The 2024 International Collegiate Programming Contest in Hubei Province, China

目录

H. Genshin Impact Startup Forbidden III

 K. Points on the Number Axis B

I. Colorful Tree


估计还会补D,I不补了,补不动了

H. Genshin Impact Startup Forbidden III

对于一个有鱼的池塘,有周围与自己本身五个关键位置可以捕获当前位位置的鱼。把这些位置存储到 map中。用四进制数 S 表示每块池塘中剩余的鱼的数目,dp[S] 表示达成该状态最少的炸弹数。枚举所有的关键位置,计算状态的转移。

#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 5, mod = 1e9 + 7;
map < PII, vector<int>>mp;
PII pos[5] = { {0,0},{0,1},{1,0},{-1,0},{0,-1} };
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	vector<int>pow(15);
	pow[0] = 1;
	for (int i = 1; i < 11; i++) {
		pow[i] = pow[i - 1] * 4;
	}
	int n, m, k;
	cin >> n >> m >> k;
	vector<int>val;
	int res = 0;
	for (int I = 0; I < k; I++)
	{
		int x, y, a;
		cin >> x >> y >> a;
		val.push_back(a);
		res += int(a*pow[I]);
		for (int i = 0; i < 5; i++)
		{
			int xx = x + pos[i].first, yy = y + pos[i].second;
			if (xx <= 0 || xx > n || yy <= 0 || yy > m) continue;
			mp[{xx, yy}].push_back(I);
		}
	}
	auto check = [&](int x)
	{
		for (int i = 0; i < k; i++) {
			if (x % 4 > val[i]) return true;
			x /= 4;
		}
		return false;
	};
	auto check2 = [&](int x, int y)
	{
		for (int i = 0; i < y; i++) {
			x /= 4;
		}
		if (x % 4 == val[y]) return true;
		return false;
	};
	vector<int>dp(int(pow[ k]),inf);
	dp[0] = 0;
	for (int i = 0; i<int(pow[k]); i++) {
		if (check(i)) continue;
		for (auto w : mp) {
			vector<int>& tmp = w.second;
			int t = i;
			for (auto ww : tmp) {
				if (check2(t,ww)) continue;
				t += int(pow[ww]);
			}
			dp[t] = min(dp[t], dp[i] + 1);
		}
	}
	cout << dp[res];
}
 
 K. Points on the Number Axis B

#define int long long//__int128 2^127-1(GCC)
#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e6 + 5, mod = 998244353;
void add(int& x, int y) {
	x += y;
	if (x >= mod) x -= mod;
}
int binpow(int a, int b) {
	if (!b) return 1;
	if (b & 1) return 1ll * a * binpow(a, b - 1) % mod;
	return binpow(1ll * a * a % mod, b >> 1);
}
int n, a[N], dp[N];
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 0; i < n; i++) cin >> a[i];
	dp[0] = 1;
	for (int i = 1; i < n; i++) {
		dp[i] = 1ll * dp[i - 1] * (i + i - 1) % mod;
		dp[i] = 1ll * dp[i] * binpow(i + i, mod - 2) % mod;
	}
	int ans = 0;
	for (int i = 0; i < n; i++) add(ans, 1ll * a[i] * dp[i] % mod * dp[n - i - 1] % mod);
	cout << ans;
}

I. Colorful Tree

本代码参考 jiangly   258662407

 大致思路是先找到白变黑的顺序将其放再vector<vector<int>>vec(q + 1);

然后黑变白就是其相反

然后按照顺序去维护每一棵树的直径,同时用并查集的方式存储每一棵树的直径,每次按事件顺序加点的时候进行更新,然后维护一个最大值更新一下就行了

新加入一棵树,且新加入的直径是(x,y)后,新直径的端点一定是(u,x)(u,y)(u,v)(v,x)(v,y)(x,y)

#define PII pair<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1500 + 11, mod = 1e9 + 7;
struct HLD {
    int n;
    std::vector<int> siz, top, dep, parent, in, out, seq;
    std::vector<std::vector<int>> adj;
    int cur;
 
    HLD() {}
    HLD(int n) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        siz.resize(n);
        top.resize(n);
        dep.resize(n);
        parent.resize(n);
        in.resize(n);
        out.resize(n);
        seq.resize(n);
        cur = 0;
        adj.assign(n, {});
    }
    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    void work(int root = 0) {
        top[root] = root;
        dep[root] = 0;
        parent[root] = -1;
        dfs1(root);
        dfs2(root);
    }
    void dfs1(int u) {
        if (parent[u] != -1) {
            adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
        }
 
        siz[u] = 1;
        for (auto& v : adj[u]) {
            parent[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }
        }
    }
    void dfs2(int u) {
        in[u] = cur++;
        seq[in[u]] = u;
        for (auto v : adj[u]) {
            top[v] = v == adj[u][0] ? top[u] : v;
            dfs2(v);
        }
        out[u] = cur;
    }
    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            }
            else {
                v = parent[top[v]];
            }
        }
        return dep[u] < dep[v] ? u : v;
    }
 
    int dist(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }
 
    int jump(int u, int k) {
        if (dep[u] < k) {
            return -1;
        }
 
        int d = dep[u] - k;
 
        while (dep[top[u]] > d) {
            u = parent[top[u]];
        }
 
        return seq[in[u] - dep[u] + d];
    }
 
    bool isAncester(int u, int v) {
        return in[u] <= in[v] && in[v] < out[u];
    }
 
    int rootedParent(int u, int v) {
        std::swap(u, v);
        if (u == v) {
            return u;
        }
        if (!isAncester(u, v)) {
            return parent[u];
        }
        auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
            return in[x] < in[y];
            }) - 1;
        return *it;
    }
 
    int rootedSize(int u, int v) {
        if (u == v) {
            return n;
        }
        if (!isAncester(v, u)) {
            return siz[v];
        }
        return n - siz[rootedParent(u, v)];
    }
 
    int rootedLca(int a, int b, int c) {
        return lca(a, b) ^ lca(b, c) ^ lca(c, a);
    }
};
 
struct DSU {
    std::vector<int> f, siz;
 
    DSU() {}
    DSU(int n) {
        init(n);
    }
 
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
 
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
 
    bool same(int x, int y) {
        return find(x) == find(y);
    }
 
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
 
    int size(int x) {
        return siz[find(x)];
    }
};
struct Diameter {
    int u;
    int v;
    int d;
};
Diameter merge(const Diameter& d1, const Diameter& d2, HLD& t) {
    Diameter res = d1;
    if (d2.d > res.d) {
        res = d2;
    }
    for (auto x : { d1.u, d1.v }) {
        for (auto y : { d2.u, d2.v }) {
            int d = t.dist(x, y);
            if (d > res.d) {
                res = { x, y, d };
            }
        }
    }
    return res;
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        int n, q;
        cin >> n >> q;
        HLD t(n);
        for (int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            u--, v--;
            t.addEdge(u, v);
        }
        t.work();
 
        vector<int>ans(q);
 
        DSU dsu(n + 1);
 
        vector<vector<int>>vec(q + 1);
        vector<int>col(n);
 
        for (int i = 0; i < q; i++) {
            int u, v;
            cin >> u >> v;
            u--, v--;
            int l = t.lca(u, v);
            for (auto x : { u,v }) {
                while (true) {
                    int y = dsu.find(x);
                    if (y == n || t.dep[y] < t.dep[l]) {
                        break;
                    }
                    col[y] = 1;
                    vec[i].push_back(y);
                    dsu.merge(y ? t.parent[y] : n, y);
                }
            }
        }
        for (int i = 0; i < n; i++) {
            if (col[i] == 0) {
                vec[q].push_back(i);
            }
        }
 
        int res = 0;
        vector<Diameter>dia(n);
        for (int i = 0; i < n; i++) {
            dia[i] = { i,i,0 };
        }
        col.assign(n, 0);
        dsu.init(n);
        auto chk = [&](int x, int y) {
            if (col[x] != col[y]) {
                return;
            }
            x = dsu.find(x), y = dsu.find(y);
            dsu.merge(x, y);
            dia[x] = merge(dia[x], dia[y], t);
            res = max(res, dia[x].d);
        };
        auto chg = [&](int x, int c) {
            col[x] = c;
            for (auto y : t.adj[x]) {
                chk(x, y);
            }
            if (x) {
                chk(x, t.parent[x]);
            }
        };
 
        for (int i = 0; i < q; i++) {
            for (auto x : vec[i]) {
                chg(x, 1);
            }
            ans[i] = res;
        }
        col.assign(n, 1);
        dsu.init(n);
        for (int i = 0; i < n; i++) {
            dia[i] = { i, i, 0 };
        }
        res = 0;
        for (int i = q - 1; i >= 0; i--) {
            for (auto x : vec[i + 1]) {
                chg(x, 0);
            }
            ans[i] = std::max(ans[i], res);
        }
 
        for (int i = 0; i < q; i++) {
            std::cout << ans[i] + 1 << "\n";
        }
    }
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值