Japan Registry Services (JPRS) Programming Contest 2025#1 (AtCoder Beginner Contest 392)


A - Shuffled Equation

点击查看代码
void solve() {
    int a, b, c;
    std::cin >> a >> b >> c;
    if (a * b == c || a * c == b || b * c == a) {
    	std::cout << "Yes\n";
    } else {
    	std::cout << "No\n";
    }
}

B - Who is Missing?

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::set<int> s;
    for (int i = 0; i < m; ++ i) {
    	int x;
    	std::cin >> x;
    	s.insert(x);
    }

    std::vector<int> ans;
    for (int i = 1; i <= n; ++ i) {
    	if (!s.count(i)) {
    		ans.push_back(i);
    	}
    }

    std::cout << ans.size() << "\n";
    for (auto & x : ans) {
    	std::cout << x << " \n"[x == ans.back()];
    }
}

C - Bib

题意:第i个人编号为qi,指向pi。求编号为i的人指向的人的编号。

编号为qi的人指向人的编号为qpi

点击查看代码
void solve() {
	int n;
	std::cin >> n;
    std::vector<int> p(n), q(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> p[i];
    	-- p[i];
    }

    for (int i = 0; i < n; ++ i) {
    	std::cin >> q[i];
    	-- q[i];
    }

    std::vector<int> ans(n);
    for (int i = 0; i < n; ++ i) {
    	ans[q[i]] = q[p[i]];
    }

    for (int i = 0; i < n; ++ i) {
    	std::cout << ans[i] + 1 << " \n"[i == n - 1];
    }
}

D - Doubles

题意:有n个骰子,每个骰子有几率投出一些数,求两个骰子骰出相同数的最大概率。

n比较小,直接枚举两个骰子,然后计算它们可以骰出来的相同数的概率和。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    const int N = 1e5 + 5;
    std::vector<int> k(n);
    std::vector<std::map<int, int> > cnt(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> k[i];
    	for (int j = 0; j < k[i]; ++ j) {
    		int x;
    		std::cin >> x;
    		++ cnt[i][x];
    	}
    }

    double ans = 0;

    for (int i = 0; i < n; ++ i) {
    	for (int j = i + 1; j < n; ++ j) {
    		double sum = 0;
    		for (auto & [x, y] : cnt[i]) {
    			if (cnt[j].count(x)) {
    				sum += 1.0 * y / k[i] * cnt[j][x] / k[j];
    			}
    		}
    		ans = std::max(ans, sum);
    	}
    }

    std::cout << std::fixed << std::setprecision(12);
    std::cout << ans << "\n";
}

E - Cables and Servers

题意:给你一个图,你可以改变某些边的连接端点使得整个图联通。

先求出每个联通块,然后每个联通块只需要size1条边,其中size是联通块的大小,那么其余的边是多余,可以用并查集求联通块和每个联通块多余的边。然后按顺序枚举所有联通块,记录前面联通块的可用边,和前面的联通块编号,每次先把前面联通块的边来连当前联通块,如果没有则用当前联通块的边尽可能连前面的联通块,模拟讨论一下就行,然后记得把没用过的边加进来,以及更新前面的联通块。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		init(_n);
	}

	void init(int _n) {
		fa.assign(_n, 0);
		cnt.assign(_n, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

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

	bool merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return false;
		}

		fa[y] = x;
		cnt[x] += cnt[y];
		return true;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::pair<int, int> > edges(m);
    DSU d(n);
    std::vector<int> id;
    for (int i = 0; i < m; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	edges[i] = {u, v};
    	if (!d.merge(u, v)) {
    		id.push_back(i);
    	}
    }

    std::vector<std::vector<int>> g(n);
    for (auto & i : id) {
    	g[d.find(edges[i].first)].push_back(i);
    }

    std::vector<std::array<int, 3>> ans;
    std::vector<int> a, b;
    for (int i = 0; i < n; ++ i) {
    	if (d.find(i) == i) {
    		if (a.size()) {
    			int j = a.back();
    			a.pop_back();
    			ans.push_back({j, edges[j].first, i});
    			d.merge(i, d.find(edges[j].first));
    			for (auto & j : g[i]) {
    				a.push_back(j);
    			}
    		} else if (g[i].size()) {
    			for (auto & j : g[i]) {
    				while (b.size() && d.same(b.back(), i)) {
    					b.pop_back();
    				}

    				if (!b.size()) {
    					a.push_back(j);
    				} else {
    					ans.push_back({j, edges[j].first, b.back()});
    					d.merge(b.back(), i);
    					b.pop_back();
    				}
    			}

    			b.push_back(i);
    		} else {
    			b.push_back(i);
    		}
    	}
    }

    std::cout << ans.size() << "\n";
    for (auto & [x, y, z] : ans) {
    	std::cout << x + 1 << " " << y + 1 << " " << z + 1 << "\n";
    }
}

F - Insert

题意:n个数依次加入序列,第i个放到第pi个,那么第pii1位置上的数都要往后移。求最终序列。

考虑从后往前做,那么最后一个数的位置是可以确定的。假设当前以及放好了i+1n,现在在放i,那么i要一直被小于等于pi的往后退,这个过程中同时pi也要变大。那么如何求pi最后的位置?考虑二分,如果pi+sum(1,mid1)>=mid那么pi的位置一定大于等于mid,这是具有单调性的,因为pi实际上是被一步一步推着往后移的。

点击查看代码
template <class T>
struct Fenwick {
    int n;
    std::vector<T> tr;

    Fenwick(int _n) {
        init(_n);
    }

    void init(int _n) {
        n = _n;
        tr.assign(_n + 1, {});
    }

    void add(int x, T v) {
        for (int i = x; i <= n; i += i & -i) {
            tr[i] += v;
        }
    }

    T query(int x) {
        T res = 0;
        for (int i = x; i; i -= i & -i) {
            res += tr[i];
        }
        return res;
    }

    T sum(int l, int r) {
        return query(r) - query(l - 1);
    }
};

void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> a[i];
    }

    Fenwick<int> tr(n);
    std::vector<int> ans(n + 1);
    for (int i = n; i >= 1; -- i) {
    	int l = a[i], r = n;
    	while (l < r) {
    		int mid = l + r + 1 >> 1;
    		if (a[i] + tr.query(mid - 1) >= mid) {
    			l = mid;
    		} else {
    			r = mid - 1;
    		}
    	}

    	int x = a[i] + tr.query(l - 1);
    	tr.add(x, 1);
    	ans[x] = i;
    }

    for (int i = 1; i <= n; ++ i) {
    	std::cout << ans[i] << " \n"[i == n];
    }
}
posted @   maburb  阅读(49)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示