Codeforces Round #805 (Div. 3)A-D

本文分享了编程竞赛中的解题思路和实战经验,包括如何快速找到最小减数达成目标、字符串处理策略、序列跳跃问题的高效解决方法以及在字符限制下优化字符串价格的算法。通过对样例的分析,深入讲解了每道题目的解决方案,并提供了相应的C++代码实现。
摘要由CSDN通过智能技术生成

最近好懒啊不想写博客,这个div3都快一个星期前的了...

Dashboard - Codeforces Round #805 (Div. 3) - Codeforces

A

题意

有 t 组询问,每组一个整数 m,求通过减去一个自然数 d 把 m 变成 10^k,这个 d 最小是多少。

思路:看下样例就好了,每次减去最近的10次方。求和

#include <bits/stdc++.h>
using namespace std;
#pragma warning(disable:4996);
#define ll long long
#define	int ll
int T, N = 2e5 + 10;
//快速幂
int  power(int  a, int  b) {
	int  ans = 1;//初始化ans,应对幂次为1和0的情况
	while (b) {
		if (b % 2 == 0) {
			b /= 2;
			a = a * a;
		}
		else {
			b -= 1;
			ans = ans * a;
			b /= 2;
			a = a * a;
		}
	}
	return ans;
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(0); cout.tie(0);
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        int l = to_string(n).length();
		cout << n - power((int)10, max((int)0, l - 1)) << endl;
    }
    return 0;
}

 B

题意:

给定一个字符串,每次只能写一个由三个不同字符组成的字符串,问写完整个字符串需要多少次。

用hash每一次每一次记录每次的写的字符,如果达到了三个,还需要继续拓展接下来的字符,直到出现了第四个不同的字符。

#include <bits/stdc++.h>
using namespace std;
#pragma warning(disable:4996);
#define ll long long
#define	int ll
int T, N = 2e5 + 10;
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(0); cout.tie(0);
    cin >> T;
    while (T--) {
		string s;
		cin >> s;
		int ans = 0;
		int sum = 0;
		vector<int>vis(300, 0);
		int ok = 0;
		for (int j = 0; j < s.length(); j++) {
			if (vis[s[j]] == 0) {
				sum++;
				ok = 1;
				vis[s[j]] = 1;
			}
			if (j + 1 < s.length() && vis[s[j+1]] == 1&&sum==3) {//达到三个接下去拓展
				continue;
			}
			if (sum ==3) {
				ans++;
				ok = 0;
				sum = 0;
				vis.assign(300,0);//重置
			}
		}
		if (sum != 0)
			ans++;//没读完三个就结束了也算一次
		ans = max(ans, (int)1);
		cout << ans << endl;
    }
    return 0;
}

C

题意:

给定一个序列arr,只能从值小的地方跳到值大的地方。给出<i,j>对问能不能在序列中由i->j。

问题在于序列的值是可以重复的,我一开始是直接双重循环,只要找到一对i和j,i<j,使得序列中一个元素i的下标小于等于另一个元素j的下标。然后被hack了。

后面想了想,只需要记录序列中i出现的最大下标和j出现的最小下标,然后比较即可。这样就快很多了。

#include <bits/stdc++.h>

using namespace std;
#pragma warning(disable:4996);
#define ll long long
#define	int ll
int T, N = 2e5 + 10;

int n, k;
void inline  inln() {}
template<class T, class ...Arg>
void inline  inln(T& t, Arg&...args) {
	cin >> t;
	inln(args...);
}
void inline pln() {
	cout << "\n";
}
template <class T, class ...Arg>
void inline pln(T t, Arg...args) {
	cout << t << " ";
	pln(args...);
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(0); cout.tie(0);
	cin >> T;
	while (T--) {
		inln(n, k);
		vector<int>arr;
		map<int, int>m, l;//m记录最早坐标,l记录最后坐标
		for (int j = 1; j <= n; j++) {
			int t;
			inln(t);
			if (!m[t])
				m[t] = j;
			l[t] = j;
		}
		while (k--) {
			int a, b;
			inln(a, b);
			int ok = 0;
			if (m[a] != 0 && m[b] != 0 && m[a] <= l[b])
				ok = 1;
			if (ok)
				pln("Yes");
			else
				pln("NO");
		}
	}
	return 0;
}

D

题意:

设 s 为一个由小写拉丁字母组成的字符串。它的价格被定义为,字符串中每个字母在字母表中的位置的和。

比如,字符串abca 的价格是 1 + 2 + 3 + 1 = 7

现在给你一个字符串 w ,和一个整数 p,请你从字符串中尽量少的移除字母,使得 w 的价格小于或等于 p 。注意移除的字母数量可以是 0 个,也可以是字符串中全部的字母。

其实很好想尽可能少的移除字母,也就是尽可能多的保留字母,所以想到先对字符串从小到大排序,然后从小开始取出需要的字母,直到将要超过停止。但是这题还很麻烦因为需要不改变相对顺序的输出剩下的字符。所以使用结构体,每个元素就是一个字符和他对应的原始序号。最后在挑出的字符里按原序列输出即可。

#include <bits/stdc++.h>

using namespace std;
#pragma warning(disable:4996);
#define ll long long
#define	int ll
int T, N = 2e5 + 10;
int n, k;
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(0); cout.tie(0);
    cin >> T;
    while (T--) {
        string s;
        int p;
        cin >> s>>p;
        if (s == "") {
            cout << "" << endl;
            continue;
        }
        if (*min_element(s.begin(), s.end()) > p + 96) {//最小的值都大于p直接返回空
            cout << "" << endl;
            continue;
        }
        vector<pair<int, int>>arr;
        for (int j = 0; j < s.length(); j++) {
            arr.push_back({ j,s[j] });
        }
        sort(arr.begin(), arr.end(), [](pair<int, int>& a, pair<int, int>& b) {
            return a.second < b.second;
            });
        vector<int>ans;
        int sum = 0;
        for (auto& x : arr) {
            if (sum + (int)x.second - 96 <= p) {
                sum += (int)x.second - 96;
                ans.push_back(x.first);
            }
            else {
                break;
            }
        }
        sort(ans.begin(), ans.end());//按原顺序输出
        for (auto& x : ans) {
            cout << s[x];
        }
        cout << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值