Codeforces Round #378 (Div. 2) 前四题题解

本文提供 CodeForces 比赛 733 的 A、B、C、D 四题的解题思路及代码实现,涵盖字符串处理、数组遍历、怪兽重量变化模拟和几何形状组合等问题。

A.Grasshopper And the String

题目链接:

http://codeforces.com/contest/733/problem/A

题目大意:

有一只蚂蚱,要跳过一串字符串,但是它只能踩在元音字母'A', 'E', 'I', 'O', 'U' 然后乱入一个’Y‘这六个字母上,然后要你求出这只蚂蚱要跳过这个字符串每一跳的最大步数(字母数)是多少。

题解:

水题。按照题目的要求来遍历一遍字符串然后到了那六个字母就记录下走过了多少个字母,然后更新一下最大步数,输出就好了。总结起来就是求字符串元音字母的最大相隔距离。

代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

#define ll long long
#define INF 0x3f3f3f3f
#define LL_INF 0x3f3f3f3f3f3f3f3f
#define MAX 1010

char str[MAX];

bool isIn(char c)
{
	if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'Y' || c == '\0')
		return true;
	return false;
}

int main()
{
	//freopen("debug\\in.txt", "r", stdin);
	//freopen("CON", "w", stdout);
	int i, j, k;
	scanf("%s", str);
	int step = 0, tmp = 0; //step是最终的步数,tmp是两个元音字母间的临时距离
	//printf("%s\n", str);
	int len = strlen(str);
	for (int i = 0; i <= len; ++i) {
		if (!isIn(str[i]) )
			tmp++;
		else {
			step = max(step, ++tmp);
			tmp = 0;
		}
	}
	printf("%d\n", step);
	return 0;
}

B.Parade

题目链接:

http://codeforces.com/contest/733/problem/B

题目大意:

某国要举行一次阅兵,现在正在为阅兵的首次抬左脚还是右脚而烦恼中。阅兵的观赏性可以用一个value值度量,value值越高表示观赏性越高。该国的观赏性值是由抬左脚的士兵数量L剪掉抬右脚的士兵数量R的绝对值得来,即value = | L - R |。现在给出每一列士兵抬左脚跟抬右脚的人数,要你选择其中的一列,交换这一列当中抬左脚跟抬右脚的人数,使得最终的观赏性value值得到尽可能地提高。没有输出0。

题解:

水题。直接照着题目的思路来就好了,分析都不用分析,遍历每一列,尝试交换,查看结果,有提高就记录没提高就抬走下一个。

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

#define ll long long
#define INF 0x3f3f3f3f
#define LL_INF 0x3f3f3f3f3f3f3f3f
#define MAX 100100

int l[MAX], r[MAX];

int main()
{
	//freopen("debug\\in.txt", "r", stdin);
	//freopen("CON", "w", stdout);
	int i, j, k;
	int n;
	scanf("%d", &n);
	int left = 0, right = 0;
	for (int i = 1; i <= n; ++i) {
		scanf("%d %d", &l[i], &r[i]);
		left += l[i];
		right += r[i];
	}
	int value = abs(left - right), index = 0;
	for (int i = 1; i <= n; ++i) {
		int v = abs((left - l[i] + r[i]) - (right - r[i] + l[i]));
		if (v > value) { //松弛操作
			value = v;
			index = i;
		}
	}
	printf("%d\n", index);
	return 0;
}


C.Epidemic in Monstropolis

题目链接:

http://codeforces.com/contest/733/problem/C

题目大意:

给你一排初始怪兽,每只怪兽给出重量。怪兽可以吃掉它相邻的重量比它低怪兽。并且怪兽们的重量遵循重量守恒定律,即吃掉了多少重量的怪兽自身就增加多少重量,吃多少长多少。现在题目给了一排目标怪兽的重量,问你初始怪兽们能不能吃呀吃,吃成目标怪兽们的重量。并且给出吃的过程。

题解:

题目有几个关键信息:

1、相邻。每只怪兽只能吃相邻的怪兽。

2、重量轻。怪兽只能吃重量比自己轻的。

3、质量守恒。吃多少长多少。

那么一步一步来。首先分析一下哪些情况不可能吃出来:

1、前后质量不守恒的。如:

初始: 2 3 3 3 3

目标: 6 6 6

前面总重量是14,后面是18,怎么可能吃成后面。

2、连续区间不可得的。因为是只能吃相邻的,所以每一个目标重量都有一段连续的初始重量相加得来。如:

初始: 2 4 4 4 4

目标: 6 6 6

目标的第一个6,可以由初始的2 4相加得来。但是第二个6就没办法由4 4得来了,所以不行。

3、连续区间内谁也吃不了谁的。如:

初始: 2 4 4 4 4

目标: 6 8 4

乍一看好像可以,但是目标的8由初始的4 4相加得来,那么这两个4谁吃谁呢?谁也吃不了谁,所以这种情况不行。

好,讨论完不可能的情况,就得来看看可以的情况,我们要怎么办了。

上述三种情况都符合的话,是不是可以求出每个目标怪兽对应的初始怪兽区间了?明显可以。

那么已经知道了目标怪兽都由哪些初始怪兽得来,剩下的是不是只需要考虑怎么个吃法了?是的。

那么是不是找到初始怪兽区间内重量最大的那一只,从那一只开始,挑一个方向吃,比如先往左边吃吃吃,吃完往右边吃吃吃,是不是吃的顺序很容易就出来了?

这就可以了。注意的是往左边吃,当前怪兽的下标会减1;往右边吃,当前怪兽下标不变,右边被吃的那只怪兽右边的所有怪兽下标都减1.     

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

#define ll long long
#define INF 0x3f3f3f3f
#define LL_INF 0x3f3f3f3f3f3f3f3f
#define MAX 550

int before[MAX], after[MAX]; //before存的是开吃之前的怪兽重量数组,after是目标的重量数组

void display(int now, int id, int l, int r, int diff)
{
	int acId = id;
	while (id > l && now > before[id-1]) { //先往左边吃
		now += before[id-1];
		printf("%d L\n", id-diff);
		id--;
	}
	while (acId < r && now > before[acId+1]) { //再往右边吃
		now += before[acId+1];
		printf("%d R\n", id-diff);
		acId++;
	}
	while (id > l && now > before[id-1]) { //最后看看能不能往左边吃,能就吃
		now += before[id-1];
		printf("%d L\n", id-diff);
		id--;
	}
}


int main()
{
	//freopen("debug\\in.txt", "r", stdin);
	//freopen("CON", "w", stdout);
	int i, j, k, n, m;
	int sum = 0;
	scanf("%d", &n);
	for (i = 1; i <= n; ++i) {
		scanf("%d", &before[i]);
		sum += before[i];
	}
	scanf("%d", &m);
	for (i = 1; i <= m; ++i) {
		scanf("%d", &after[i]);
		sum -= after[i];
	}
	if (sum) {  //前后两者的重量不守恒的话说明肯定不可能
		printf("NO\n");
		return 0;
	}
	int tmp = 0, last = 0, maxn = 0, max_index = 0, cnt = 1;
	pair<int, int> index[MAX]; //index[j]存的是after[j]对应的before区间的起始位置以及终止位置
	int maxn_index[MAX];	//maxn_index[j]存的是index[j]区间内的最大值,方便最后输出
	for (i = j = 1; i <= n && j <= m; ++i) { //开始匹配,从before中找寻一段区间[last, i]来组成after[j]
		tmp += before[i];
		if (before[i] > maxn) {
			maxn = before[i];
			max_index = i;
		}
		if (tmp == after[j]) {
			if (tmp / (i - last) == maxn && (i - last) > 1) { 
				printf("NO\n"); 	//在这一段区间内的重量都一样的,你吃不了我我也吃不了你,所以这种情况也是不可能的
				return 0;
			}
			j++;
			tmp = 0;
			maxn = 0;
			index[cnt] = make_pair(last + 1, i);
			maxn_index[cnt] = max_index;
			last = i;
			cnt++;
		}
		if (tmp > after[j]) {
			printf("NO\n"); //因为是连续的,所以一旦一段连续的区间无法组成目标重量,就说明不可能了
			return 0;
		}
	}
	if (i-1 != n || j-1 != m) {
		printf("NO\n"); //匹配了一遍发现多出来了几只怪兽或者缺了几只怪兽,那肯定也是不行的
		return 0;
	}
	int diff = 0;
	printf("YES\n");
	for (i = 1; i < cnt; ++i) {
		int id = maxn_index[i];
		int l = index[i].first, r = index[i].second;
		if (id == l) {
			while (before[id] == before[id+1] && id < r)
				id++;
		}
		int now = before[id];
		display(now, id, l, r, diff); //开吃
		diff += r - l;
	}
	return 0;
}

PS:这道题如果改成初始怪兽们可以随机吃呢?该怎么算?留给我思考。


D.Kostya the Sculptor

题目链接:

http://codeforces.com/contest/733/problem/D

题目大意:

给你一堆的长方体石头,取其中的两个拼成一个更大的长方体石头,求取哪两个石头使得这个更~大的长方体石头的内切球半径最大。

题解:

想要拼的起来,那么就得保证两个石头的至少一个面相同,也就是长、宽都相等。而且内切球的半径大小取决于长方体的最短边。

那么将所有长方体按最长边与次长边排个序,最长边与次长边相同的两个长方体来拼拼看,比较比较,就可以了。

一开始逗逼了,把长方体按长、宽、高相同数据不同分类分成六种长方体,排个序,然后同高同宽的两两拼一下,直接把复杂度搞成O(n!),弄了半天都没发现。其实只需要排个序,然后相邻两个试着拼一下就可以了(仍不理解为什么,留着以后看),复杂度O(nlogn),取决于排序算法的复杂度。

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

#define ll long long
#define INF 0x3f3f3f3f
#define LL_INF 0x3f3f3f3f3f3f3f3f
#define MAX 100100

typedef struct Rectangle
{
	int a, b, c; //a,b是最长边与次长边,c是最短边
	int index; //原来输入的顺序下标

	Rectangle() : a(0), b(0), c(0), index(0) {}
	Rectangle(int i, int j, int k, int l) : a(i), b(j), c(k), index(l) {}
	// bool operator < (const Rectangle &r) {
	// 	if (a != r.a)
	// 		return a < r.a;
	// 	else if (b != r.b)
	// 		return b < r.b;
	// 	else
	// 		return c < r.c;
	// } //写个关系运算符重载搞了半天没成功
}Rec;

Rec rect[MAX * 6];

void display(int n)
{
	for (int i = 1; i <= 2 * n; ++i)
		printf("%d %d %d %d\n", rect[i].a, rect[i].b, rect[i].c, rect[i].index);
}

bool cmp(Rec r1, Rec r2)
{
	if (r1.a != r2.a)
		return r1.a < r2.a;
	else if (r1.b != r2.b)
		return r1.b < r2.b;
	else
		return r1.c < r2.c;
} 

int main()
{
	//freopen("debug\\in.txt", "r", stdin);
	//freopen("CON", "w", stdout);
	int i, j, k;
	int n, maxn = 0, first = 0, second = 0; //maxn是最大的组合,first表示第一个石头的下标,second是第二个,可为0
	scanf("%d", &n);
	int a, b, c;
	for (i = 1; i <= n; ++i) {
		scanf("%d %d %d", &a, &b, &c);
		int l1, l2, l3;
		l1 = max(max(a, b), c);
		l3 = min(min(a, b), c);
		l2 = a + b + c - l1 - l3;
		rect[i] = Rectangle(l1, l2, l3, i);
		if (l3 > maxn) { //选一个石头的情况,选出最大的一个
			maxn = l3;
			first = i;
		}
	}
	sort(rect, rect + n, cmp);
	//display(n);
	int minw = 0;
	for (i = 1; i <= n; ++i) {
		if (rect[i].a == rect[i+1].a && rect[i].b == rect[i+1].b) { //因为排好序了所以相邻的组合一下试试看就可以了
			minw = min(min(rect[i].a, rect[i].b), rect[i].c + rect[i+1].c);
			if (minw > maxn) {
				maxn = minw;
				first = rect[i].index;
				second = rect[i+1].index;
			}
		}
	}
	if (second)
		printf("2\n%d %d\n", first, second);
	else
		printf("1\n%d\n", first);
	return 0;
}






跟网型逆变器小干扰稳定性分析与控制策略优化研究(Simulink仿真实现)内容概要:本文围绕跟网型逆变器的小干扰稳定性展开分析,重点研究其在电力系统中的动态响应特性及控制策略优化问。通过构建基于Simulink的仿真模型,对逆变器在不同工况下的小信号稳定性进行建模与分析,识别系统可能存在的振荡风险,并提出相应的控制优化方法以提升系统稳定性和动态性能。研究内容涵盖数学建模、稳定性判据分析、控制器设计与参数优化,并结合仿真验证所提策略的有效性,为新能源并网系统的稳定运行提供理论支持和技术参考。; 适合人群:具备电力电子、自动控制或电力系统相关背景,熟悉Matlab/Simulink仿真工具,从事新能源并网、微电网或电力系统稳定性研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 分析跟网型逆变器在弱电网条件下的小干扰稳定性问;② 设计并优化逆变器外环与内环控制器以提升系统阻尼特性;③ 利用Simulink搭建仿真模型验证理论分析与控制策略的有效性;④ 支持科研论文撰写、课研究或工程项目中的稳定性评估与改进。; 阅读建议:建议读者结合文中提供的Simulink仿真模型,深入理解状态空间建模、特征值分析及控制器设计过程,重点关注控制参数变化对系统极点分布的影响,并通过动手仿真加深对小干扰稳定性机理的认识。
### 完美排列问分析 对于 Codeforces Round 1007 (Div. 2) 中的 **B. Perfecto** 问,目标是找到一个长度为 \( n \) 的完美排列。如果这样的排列存在,则输出该排列;否则输出 `-1`。 #### 目解析 目定义了一个“完美排列”,其条件如下: - 对于任意位置 \( i \),满足 \( |p_i - p_{i+1}| = 1 \) 或者 \( |p_i - p_{i+1}| = n-1 \)[^2]。 这意味着相邻两个元素之间的差值要么等于 1(即连续),要么等于 \( n-1 \)(即首尾相连)。 ####方法 通过观察和归纳可以得出以下结论: - 当 \( n \% 3 == 0 \) 或 \( n \% 3 == 2 \) 时,无法构建出符合上述条件的完美排列。 - 而当 \( n \% 3 == 1 \) 时,可以通过特定构造方式生成所需排列。 具体实现逻辑如下: ```cpp #include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; if (n % 3 != 1) { // 如果不符合模数条件 cout << "-1\n"; return; } vector<int> res(n); bool flag = true; // 控制交替模式 for(int i = 0;i < n;i++) { if(flag){ res[i] = i + 1; } else{ res[i] = ((n-i)+1)%n; if(res[i]==0)res[i]=n; } flag=!flag; } for(auto num : res){ cout<<num<<" "; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); int t=1; while(t--){ solve(); } } ``` 此代码片段实现了基于输入大小 \( n \) 来判断是否存在合法解并输出相应结果的功能。 #### 关键点说明 - 判断依据来源于对不同余数值下能否形成循环结构的研究成果。 - 构造过程中采用交替填充策略来确保最终序列能够满足绝对差的要求。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值