最近好懒啊不想写博客,这个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;
}