Codeforces Round 790 (Div. 4)题解ABCDEFGH1H2

A. Lucky?

题意:给你 T 个由六个数字组成的票据,如果票据的前三个数字之和和后三个数字之和相等,则输出 YES ,否则输出 NO

思路:模拟即可

    string s;
	cin >> s;
	int l= 0 , r = 0;
	l += s[0] - '0';
	l += s[1]- '0';
	l += s[2]- '0';
	r += s[3]- '0';
	r += s[4]- '0';
	r += s[5]- '0';
	if(l == r)cout <<"YES\n";
	else cout <<"NO\n";

B. Equal Candies

题意:有 n 盒糖,第 i 盒糖中有 ai​ 颗糖。你有 n 个朋友,你想给每个朋友发一盒糖。但是每盒糖的数量可能不一样,所以你想要吃掉一些糖,使得每盒糖中糖数相等。

注意:你可以在不同的盒子中吃掉不同数量的糖(可以不吃),但不能向任何盒子中加糖。

问你最少吃掉多少颗糖,才能完成目标。

思路:注意到给糖的数量仅收到最小值的影响,所以遍历一下找到以后开始计入答案即可

    int n;
	cin >> n;
	for(int i = 1;i<=n;i++)cin >>q[i];
	int min_val = INF;
	for(int i = 1;i<=n;i++)min_val = min(q[i],min_val);
	LL ans = 0;
	for(int i = 1;i<=n;i++)ans += q[i] - min_val;
	cout << ans << endl;

C. Most Similar Words

题意:你有 n 个长度为 m 的单词,第 i 个单词是 si​。在一个操作中,你可以把任何一个单词的任何一个位置上的字母改成它相邻的字母,我们定义si​ 与 sj​ 的差异度为使 si​=sj​ 所需的操作次数,如 "best" 与 "cost" 差异度为 1+10+0+0=11。

你要找到 si​ 与 sj​(满足 i<j)的差异度的最小值,也就是每一对单词差异度的最小值。

思路:注意到题目要求找到没两个单词之间最小的差异度,所以直接遍历一下找最小值即可

    int n , m;
	cin >> n >> m;
	vector<string> alls(n);
	for(int i = 0;i<n;i++)cin >>alls[i];
	
	vector<int> ans;
	
	for(int i = 0;i<n;i++){
		int temp = 0;
		for(int j = i+1;j<n;j++){
			for(int k = 0;k<m;k++){
					temp += abs(alls[i][k] - alls[j][k]);
			}
			ans.push_back(temp);
			temp = 0;
		}
	}
	sort(ans.begin(),ans.end());
	cout << ans[0]<<endl;

D. X-Sum

题意:有一个 n×m 的国际象棋盘 a,(i,j) 上有一个非负整数 aij​。

你要在上面放一个象,问它能攻击到的点上的非负整数和最大是多少。

(象走斜线,无距离限制,可以参考样例解释)

注意:象所在的点也是它能攻击到的点。

思路:二维平面过某点两条对角线上元素最大值,给过当前点的两条对角线计入元素,查询的时候直接查询两条对角线贡献再去重一次,即有O1的时间复杂度

    int t;
    cin >> t;
	while(t--)
	{
		int n , m;
        cin >> n >> m;
        vector<int> l(n+1,0),r(n+1,0);
        int ans = 0;
		for(int i = 1;i <= n;++i)
			for(int j = 1;j <= m;++j)
				cin >> a[i][j];
                l[i + j] += a[i][j], r[i - j + m] += a[i][j];
		for(int i = 1, t;i <= n;++i)
			for(int j = 1;j <= m;++j)
				if((t = l[i + j] + r[i - j + m] - a[i][j]) > ans) ans = t;
		cout << ans <<endl;
	}
	return 0;

E. Eating Queries

题意:

有 n 颗糖,吃第 i 颗糖可以得到 ai​ 的糖分。

有 q 次询问,每次询问最少吃多少颗糖可以得到不小于 x 的糖分,无解输出 -1

思路:为了找到最小的次数,肯定希望先吃大的。从大到小排序以后记录一下前缀和,然后查询的时候使用二分即可,超出总和则答案为-1

    int n , q;
	cin >> n >>q;
	LL sum = 0;
	vector<LL> a(n);
	for(int i = 0;i<n;i++){
		cin >> a[i];
		sum += a[i];
	}
	vector<pair<LL,LL>> alls;
	sort(a.begin(),a.end(),greater<LL>());
	LL temp = 0;
	for(int i = 0;i<n;i++){
		temp += a[i];
		alls.push_back({temp,i+1});
	}
	while(q--){
		LL x;
		cin >>x;
		if( x > sum){
			cout <<"-1" << endl;
		}
		else{
			LL l = 0, r = n-1;
			while( l < r){
				LL mid = l + r >>1;
				if(alls[mid].first >= x) r = mid;
				else l = mid + 1;
			}
			cout << alls[l].second << endl;
		}
	}

F. Longest Strike

题意:

给你一个长度为 n 的序列 a 和一个整数 k,你要求一个区间 [l,r] 满足:

对于任何整数 x∈[l,r],x 在 a 中的出现次数不少于 k 次。

最大化 r−l。

思路:观察到题目让我们找一个其中任意元素在数列a中出现不少于 k 次的区间。而不是在从 l~r的每个数在a中出现k次。所以数列排序并没有影响,那么可以将这个数列排序,把数组中出现次数大于 k 的数按顺序拎出来

那么直接开一个map记录出现次数 >=k的,然后找最长连续区间即可

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n , k;
		cin >> n >> k;
		vector<int> a(n);
		map<int,int> mp;
		for(int i = 0;i<n;i++){
			cin >> a[i];
			mp[a[i]]++;
		}
		deque<int> f;
		for(PII i : mp){
			if(i.se >= k)f.pb(i.fi);
		}
		vector<array<int,3>> ans;
		if(f.empty())cout <<"-1\n";
		else{
			while(!f.empty()){
				int l = f.front();
				int r;
				int cnt = 0;
				int last = f.front() - 1;
				while(!f.empty() && f.front() == last+1){
					last = f.front();
					r = last;
					cnt++;
					f.ppf();
				}
				ans.pb({cnt , l , r});
			}
			sort(all(ans),[&](array<int,3>a,array<int,3>b){
				return a[0] > b[0];	
			});
			cout << ans[0][1] <<" " << ans[0][2] << endl;
		}
	}

G. White-Black Balanced Subtrees

题意:给定一棵 n 个结点的树,根结点是 1,每个结点是黑色或白色的。如果一棵树中黑色结点与白色结点数量相同,那么这棵树是“平衡的"。问这棵 n 个结点的树有多少棵“平衡的”子树。

思路:从根开始往下遍历每个孩子,到尾部计算是否平衡,这里可以让黑白变成 - 1 1,和为0即可平衡

变形的dfs,想到如何建立平衡的模型即可

vector<int> v[N];
int color[N];
int ans;
int n, fa;
char c;

int dfs(int now) {
	int sum = color[now];
	for (int i = 0; i < v[now].size(); i++) {
		sum += dfs(v[now][i]);
	}
	if (sum == 0) ans++;
	return sum;
}
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) v[i].clear();
	ans = 0;
	for (int i = 2; i <= n; i++) {
		cin >> fa;
		v[fa].push_back(i);
	}
	for (int i = 1; i <= n; i++) {
		cin >> c;
		if (c == 'W') color[i] = -1;
		else color[i] = 1;
	}
	dfs(1);
	cout << ans << endl;
}

H1,H2:

题意:

一个终端是一排 n 个连接在一起的相等的线段,有两个终端,一上一下。

有一个数组 ai​,代表从上面的终端中第 i 条线段,到下面的终端中第 ai​ 条线段,有一条连线。

问这些连线最多有几个交点。

H1:N <1000,

H2:N<1e5+10

思路:考虑什么时候会产生交点,我们设第一条线段上面为 x1,下面为y1,第二条为x2,y2,那么只有两种情况会产生交点

1:x1 < x2 && y1 > y2

2:x1 > x2 && y1 < y2

显然这是一个逆序对的变形,使用归并排序即可

由于H1数据范围较小,可以使用On^2的时间复杂度暴力便利,此处不给出代码

    int test_case;
	cin >> test_case;
	while (test_case--){
		int n;cin >> n;
		int ans = 0;
		for (int i = 1; i <= n; i++)cin >> a[i];
		auto merge_sort = [&](auto merge_sort,int l ,int r)->void{
			if (l == r) return ;
			int mid = l + r >> 1;
			merge_sort(merge_sort,l, mid), merge_sort(merge_sort,mid + 1, r);
			for (int i = l, j = mid + 1; j <= r; j++){
				while (i <= mid && a[i] < a[j]) i++;
				ans += mid - i + 1;
			}
			int pl = l, pr = mid + 1, p = l;
			while (pl <= mid && pr <= r)t[p++] = a[pl] < a[pr] ? a[pl++] : a[pr++];
			while (pl <= mid) t[p++] = a[pl++];
			while (pr <= r) t[p++] = a[pr++];
			for (int i = l; i <= r; i++) a[i] = t[i];
		};
		merge_sort(merge_sort,1, n);
		cout << ans << endl;
	}

### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值