Educational Codeforces Round 151 (Rated for Div. 2) 感想



感想

不会写,写的好墨迹


A. Forbidden Integer

1.题目内容

题目地址

2.个人思路

如果1可用就全堆1,否则如果是偶数就全堆2,是奇数就全堆2加一个3
判断一下k能不能取到2和3就可以。

3.代码


int main() {
	cin >> t;
	while (t--) {
		ll k, x;
		cin >> n >> k >> x;
		vector<ll> ans;
		if (x != 1) {
			cout << "YES\n";
			cout << n << "\n";
			for (int i = 1; i <= n; i++) {
				cout << "1 ";
			}
			cout << "\n";
		}
		else {
			if (n % 2 == 0) {
				if (k < 2) {
					cout << "NO\n";
				}
				else {
					cout << "YES\n";
					cout << n / 2 << "\n";
					for (int i = 1; i <= n / 2; i++) {
						cout << "2 ";
					}
					cout << "\n";
				}
			}
			else {
				if (k < 3) {
					cout << "NO\n";
				}
				else {
					cout << "YES\n";
					cout << n / 2 << "\n";
					for (int i = 1; i <= n / 2 - 1; i++) {
						cout << "2 ";
					}
					cout << "3\n";
				}
			}
		}
	}
	return 0;
}

B. Come Together

1.题目内容

题目地址

2.个人思路

以A为中心建立坐标轴,判断一下两个人的家的象限,如果相同就是两个坐标分别取最小相加再加1,如果分别位于1 4或2 3就是最小的x轴 + 1
如果分别位于1 2或3 4就是最小的y轴 + 1,如果分别位于1 3或2 4就是1.
证明的话画一下就能看出来。

3.代码


int main() {
	cin >> t;
	while (t--) {
		ll x, y;
		cin >> x >> y;
		ll a, b, c, d;
		cin >> a >> b;
		cin >> c >> d;
		ll bx = (x - a), by = (y - b);
		ll cx = (x - c), cy = (y - d);
		if (bx * cx <= 0 && by * cy <= 0) {
			cout << "1\n";
		}
		else if (bx * cx <= 0 && by * cy > 0) {
			cout << min(abs(by), abs(cy)) + 1 << "\n";
		}
		else if (bx * cx > 0 && by * cy <= 0) {
			cout << min(abs(bx), abs(cx)) + 1 << "\n";
		}
		else if (bx * cx > 0 && by * cy > 0) {
			cout << min(abs(bx), abs(cx)) + min(abs(cy), abs(by)) + 1 << "\n";
		}
	}
	return 0;
}

C. Strong Password

1.题目内容

题目地址

2.个人思路

贪心,显然前面的密码选取的第一次出现位置越靠后,剩下的数据库长度就越短,能碰到相应数字的概率就越低,所以每次都选择当前在数据库种最靠后的位置的数字,然后判断是否每个都能取到就可以。

3.代码


ll t, n, m, p = 998244353;
ll arr[200005], sum[300005][10];
set<ll> pos[10];
 
int main() {
	cin >> t;
	while (t--) {
		string s;
		cin >> s;
		n = s.size();
		cin >> m;
		string l, r;
		cin >> l >> r;
		for (int i = 0; i < 10; i++) {
			pos[i].clear();
			sum[0][i] = 0;
		}
		for (int i = 0; i < n; i++) {
			ll tmp = s[i] - '0';
			pos[tmp].insert(i);
		}
		bool ans = false;
		ll ma = -1, mp = -1, now = -1;
		for (int i = 0; i < m; i++) {
			for (int j = l[i] - '0'; j <= r[i] - '0'; j++) {
				auto x = pos[j].upper_bound(now);
				if (x == pos[j].end()) {
					ans = true;
					break;
				}
				if (*x > ma) {
					ma = *x;
					mp = j;
				}
			}
			if (ans) break;
			now = ma;
		}
		if (ans) {
			cout << "YES\n";
		}
		else {
			cout << "NO\n";
		}
	}
	return 0;
}

D - Rating System

1.题目内容

题目地址

2.个人思路

dp转移,k的值为前i个数字的前缀和,最大值的对应k集合中一定至少会有一个1~x的前缀和。
问题转化成在1~x的前缀和下的最优结果,考虑dp。
dp[i]为以1~i - 1的前缀和为k(i == 1 时为0)时,i到n的变化让rating带来的提升。(为什么不是真正的提升,因为假设1 ~ i - 1的前缀和为x,在i - 1之前可能已经到达或者超过过x,那么这个结果就不好算了,而且实际上最优情况下1 ~ i - 1不应该存在超过前缀和的点,所以说dp的转移是正确的。)
从后往前dp,如果arr[i]大于0,那么这个点不应该用来转移,因为一定会不是最优点,如果小于0,有两种情况:
后面的前缀和不会低于sum[i]:dp[i]就是arr[i]的绝对值。

dp[i] = abs(arr[i])

存在后面的前缀和低于sum[i]:假设后面最近的低于i的位置low,那么:

dp[i] = dp[low] - (sum[low - 1] - sum[i - 1])

可以理解为,因为sum[low]前缀和小于low,所以到 low 之后的变化应该和dp[low]接近,但是带来的增益会因为sum的变化而变化。
可以考虑 -1 2 -3这个例子,在i = 3时,他是以前缀和为1([1, 2])进行增减,而在i = 1时,因为它前面是0,所以转移到3的时候需要把[1, 2]减掉才是3在i = 1的情况下实际变化到的数字(也就是sum[0] = 0)。
单调栈处理出第一个小于当前前缀和的数字,然后dp处理,最后比较最大输出结果即可。

其实我也不知道我说的对不对,希望有人指点下

3.代码

ll t, n, m, p = 998244353;
ll arr[300005], sum[300005];
ll dp[300005], low[300005];
 
int main() {
	cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> arr[i];
			low[i] = 0;
			sum[i] = sum[i - 1] + arr[i];
		}
		ll k = 0, nn = -1;
		stack<ll> sto;
		for (int i = 1; i <= n; i++) {
			while (!sto.empty() && sum[sto.top()] > sum[i]) {
				low[sto.top()] = i;
				sto.pop();
			}
			sto.push(i);
		}
		for (int i = n; i > 0; i--) {
			if (arr[i] > 0) {
				dp[i] = -1;
			}
			else {
				if (low[i]) {
					dp[i] = dp[low[i]] - sum[low[i] - 1] + sum[i - 1];
				}
				else dp[i] = abs(arr[i]);
			}
		}
		for (int i = 1; i <= n; i++) {
			if (nn < dp[i]) {
				nn = dp[i];
				k = sum[i - 1];
			}
		}
		cout << k << "\n";
	}
	return 0;
}

其他想法

D的转移并非当前状态的真正最优解,只是使用局部最优来处理,我也不知道对不对,急了就开始魔怔了。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值