2023杭电多校第四场 - 3 6 10 11 12

比赛地址:传送门

赛时过了 5 题,但是题目出得慢,罚时有点高
3 尺取法
6 求古典概型期望 数学,队友出
7 数学,队友出
10 规律题
11 floyd 求最小环长度和个数
12 签到题,贪心

1003 Simple Set Problem

题意
给你 k 个 multiset,让你从每个集合中选一个数组成一个新的集合,问你新集合中数的最大值与最小值的差值最小是多少?

思路
将所有的数按照 {数,集合归属} 的方式存储,再按照数的递增顺序排序,再利用尺取法取所有集合编号更新答案即可。注意数字范围大小

代码

//>>>Qiansui
void solve(){
	int n, num = 0;
	cin >> n;
	vector<pll> a;
	for(int i = 0; i < n; ++ i){
		ll c, t;
		cin >> c;
		num += c;
		while(c--){
			cin >> t;
			a.push_back({t, i});
		}
	}
	sort(a.begin(), a.end());
	ll l = 0, r = 0, lei = 0, ans = -1;
	vector<int> cnt(n + 1, 0);
	while(r < num){
		while(lei < n && r < num){
			++ cnt[a[r].second];
			if(cnt[a[r].second] == 1){
				++ lei;
			}
			++ r;
			if(lei == n) break;
		}
		if(r == num && lei != n) break;
		-- r;
		while(cnt[a[l].second] > 1 && l < r){
			-- cnt[a[l].second];
			++ l;
		}
		if(ans == -1) ans = a[r].first - a[l].first;
		else ans = min(ans, a[r].first - a[l].first);
		-- cnt[a[l].second];
		-- lei;
		++ l;
		++ r;
	}
	cout << ans << '\n';
	return ;
}

1006 PSO

题意
n 个物体,n - 1 个独立连在中心一个上。问你不同的两个物体之间传消息的路径数 X 的期望和最大值。
\(2 \le n \le 10^9\)
思路
古典概型
\(n = 2\) 时,\(X\) 可能取值为 1,期望为 1,最大值为 1
\(n > 2\) 时,\(X\) 可能取值为 1,2,那么\(P(X = 1) = \frac{n - 1}{C_{n}^{2}}\),$P(X = 2) = \frac{C_{n - 1}^{2}} {C_{n}^{2}} $,所以期望 $E = \frac{2n - 2}{n} $,最大值为 2

注意 \(n = 2\) 时需要特判最大值!!!

代码

void solve(){
	int n;
	cin >> n;
	double ans = 2.0 * (n - 1.0) / n, m = 2.0;
	if(n == 2) m = 1.0;
	cout << fixed << setprecision(9) << ans << ' ' << m << '\n';
	return ;
}

1010 Kong Ming Qi

题意
详见题面
孔明棋最后剩下的棋数最少个数

思路
详见链接,有空再写结论,证明就没戏了
https://blog.csdn.net/u014609452/article/details/53523846
赛时打表~~~
image

代码

void solve(){
	int n, m;
	cin >> n >> m;
	if(m < n) swap(n, m);
	if(n == 1) cout << (m + 1) / 2 << '\n';
	else if(n % 3 == 0 || m % 3 == 0) cout << 2 << '\n';
	else cout << 1 << '\n';
	return ;
}

1011 Circuit

题意
求给定有向图最小环的长度和个数

思路
求最小环的长度和个数。利用 floyd 算法即可求解
注意取模仅对个数取模!

代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const ll maxm = 5e2 + 5, inf = 1e18, mod = 998244353;

void solve(){
	int n, m;
	cin >> n >> m;
	vector<vector<ll>> d(n + 1, vector<ll>(n + 1, inf)), cnt(n + 1, vector<ll>(n + 1, 0));
	vector<vector<ll>> g(n + 1, vector<ll>(n + 1, inf));
	for(int i = 0; i < m; ++ i){
		ll u, v, w;
		cin >> u >> v >> w;
		d[u][v] = g[u][v] = min(g[u][v], w);
		cnt[u][v] = 1;
	}
	ll res = inf, ans = 0;
	for(int k = 1; k <= n; ++ k){
		for(int i = 1; i < k; ++ i){
			if(res > d[i][k] + g[k][i]){
				res = d[i][k] + g[k][i];
				ans = cnt[i][k] % mod;
			}else if(res == d[i][k] + g[k][i]){
				ans = (ans + cnt[i][k]) % mod;
			}
		}
		for(int i = 1; i <= n; ++ i){
			for(int j = 1; j <= n; ++ j){
				if(d[i][j] > d[i][k] + d[k][j]){
					d[i][j] = d[i][k] + d[k][j];
					cnt[i][j] = (cnt[i][k] * cnt[k][j]) % mod;
				}else if(d[i][j] == d[i][k] + d[k][j]){
					cnt[i][j] = (cnt[i][j] + cnt[i][k] * cnt[k][j] % mod) % mod;
				}
			}
		}
	}
	if(res == inf) cout << "-1 -1\n";
	else cout << res << ' ' << ans % mod << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}


1012 a-b Problem

题意
Alice 和 Bob 先后取石头,同一块石头不同的人取获得的分数不同,每个人都想尽可能的最大化相互之间的分数差,想要自己的分数减去对手的分数的差值尽可能大。问你最后结束时两人的取得的石头总分数差?

思路
考虑转化一下问题,假如一开始所有石子全在 Bob 手里,那么题中轮到 Alice 取时就拿走一个 Bob 手中的石子,轮到 Bob 取时 Bob 就藏起来一个石子不让 Alice 拿,这样显然与之前的问题等价。然后 Alice 取时自己获得 Ai 的分数,Bob 失去 Bi 的分数,相当于拉开了 Ai + Bi 点分数差,所以 Alice 一定会优先取 Ai + Bi 最大的石子,而 Bob 也会优先藏住 Ai + Bi 最大的石子,所以只需要按 Ai + Bi 排序再轮流按顺序取即可。

代码

//>>>Qiansui
void solve(){
	int n;
	cin >> n;
	ll x, y;
	vector<pll> p;
	for(int i = 0; i < n; ++ i){
		cin >> x >> y;
		p.push_back({x + y, y});
	}
	sort(p.begin(), p.end());
	y = n - 1;
	ll ans = 0;
	while(y >= 0){
		ans += p[y].first - p[y].second;
		if(y == 0){
			break;
		}
		ans -= p[y - 1].second;
		y -= 2;
	}
	cout << ans << '\n';
	return ;
}
posted on 2023-07-27 20:17  Qiansui  阅读(46)  评论(0编辑  收藏  举报