内测人员,写个简易题解。
A.小苯吃糖果
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 2e5;
#endif
int main() {
array<int, 3> a;
for (auto& i : a) {
cin >> i;
}
sort(a.begin(), a.end());
cout << max(a[2], a[0] + a[1]);
return 0;
}
B. 小苯的排列构造
尝试构造:
,只有
符合,
。
,发现
符合,
。
于是发现规律:
一大一小凑一对,构造出的数组是
个
。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 1e6;
#endif
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cout << n - i + 1 << " ";
}
cout << endl;
}
int main() {
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
C. 小苯的最小整数
总共最大才位数,枚举所有情况取
min
就好了。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 2e5;
#endif
int main() {
int T;
cin >> T;
while (T--) {
string s;
cin >> s;
LL ans = stoll(s);
for (int i = 0; i < s.size(); ++i) {
s = s.substr(1) + s[0];
ans = min(ans, stoll(s));
}
cout << ans << endl;
}
return 0;
}
D. 小苯的蓄水池(easy)
直接循环就好了。没写,直接写的hard。
E. 小苯的蓄水池(hard)
用一个set
维护隔板。
其中表示
和
之间的隔板。
①对于删除操作,循环过去把隔板从set
删除就好了。
②对于查询操作,分别找到第 个水池的前一个隔板和后一个隔板。通过
set
的lower_bound
找到后一个隔板,--
运算符移动迭代器找到前一个隔板。然后前缀和求出区间和。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 2e5;
#endif
int a[N], n, m;
set<int> st;
LL pre[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
st.insert(i);
pre[i] = pre[i - 1] + a[i];
}
while (m--) {
int op, l, r, p;
cin >> op;
if (op == 1) {
cin >> l >> r;
auto p = st.lower_bound(l);
while (*p < r) {
p = st.erase(p);
}
} else {
cin >> p;
auto it = st.lower_bound(p);
int r = *it;
int l = 1;
if (it != st.begin()) {
--it;
l = *it + 1;
}
cout << fixed << setprecision(8) << 1.0 * (pre[r] - pre[l - 1]) / (r - l + 1) << endl;
}
}
return 0;
}
F. 小苯的字符提前
字典序肯定有传递性的。
用sort
对每一个位置,按照字典序排序。
比较字典序时,不能for
过去比较,得想办法加速。
画图,如下,假设要比较位置和
的字典序,假定
。
①和
移到最前面,如果不相等,直接根据
和
得到字典序大小。
②前面的字符不需要比较,因为对应位置一样。
③根据上图,如果移动到前面,这一部分
不移动;如果移动
到前面,这一部分
往前移动一个位置,从而和
对应上。
用一个数组,
表示从
开始,最小的
,
和
不相同的。
⑤如果大于等于
,那么说明这段都相同。
并且又因为后面没有移动,完全一样,那么说明
和
两个位置得到的字符串完全一样。
sort
完之后,拿到第小的下标,按题目的定义输出就行了。
优化: 内测群友说可以线性,nth,于是把代码中的
sort(p + 1, p + n + 1, [&](int x, int y) -> int {
替换成
nth_element(p + 1, p + k, p + n + 1, [&](int x, int y) -> int
从变成
。这太有意思了。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 1e6;
#endif
int n, k;
char s[N];
int next_not_equal[N];
int p[N];
void solve() {
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
}
next_not_equal[n] = n;
for (int i = n - 1; i >= 1; --i) {
next_not_equal[i] = next_not_equal[i + 1];
if (s[i] != s[i + 1]) {
next_not_equal[i] = i;
}
}
for (int i = 1; i <= n; ++i) {
p[i] = i;
}
sort(p + 1, p + n + 1, [&](int x, int y) -> int {
if (s[x] != s[y]) {
return s[x] < s[y];
}
if (x < y) {
if (next_not_equal[x] >= y) {
return 0;
}
return s[next_not_equal[x] + 1] < s[next_not_equal[x]];
} else {
if (next_not_equal[y] >= x) {
return 0;
}
return s[next_not_equal[y]] < s[next_not_equal[y] + 1];
}
});
int z = p[k];
cout << s[z];
for (int i = 1; i < z; ++i) {
cout << s[i];
}
for (int i = z + 1; i <= n; ++i) {
cout << s[i];
}
cout << endl;
}
int main() {
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
G. 小苯的数位MEX
从大到小枚举mex
,因为数字是到
,
从
到
。
根据题意给的操作,能变成
这个区间的数据。
用数位
dp
求有多少个数字的
是枚举的
mex
。
如果个数大于,说明找到了答案,输出这个枚举的
mex
和个数。
dp
数组含义:
,从高位起第
到
位,拥有的数字用
这个集合表示。如果把这个状态的数字凑完整,会有
个数字的
mex
是枚举的mex
。这个值没有数字上限和前导零的限制。
内测小故事:原本题意是到
的
mex
值的总和。但是现在要稍微计算一下,还要枚举
mex
,好没意思的改题方式。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
struct Lemon {
Lemon() {
ios::sync_with_stdio(false);
cin.tie(0);
}
} lemon;
#define lson (k << 1)
#define rson (k << 1 | 1)
const int mod = 7 + 1e9;
// const int mod = 998244353;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
#if LEMON
const int N = 3 + 111;
#else
const int N = 3 + 1e6;
#endif
int dp[12][1024];
int p, a[N];
int dfs(int p, int limit, int lead, int st, int m) {
if (!p) {
int mex = 0;
while (st >> mex & 1) {
++mex;
}
return mex == m;
}
if (!limit && !lead && dp[p][st] != -1) {
return dp[p][st];
}
int ans = 0;
int up = limit ? a[p] : 9;
for (int i = 0; i <= up; ++i) {
if (lead && i == 0) {
ans += dfs(p - 1, limit && i == up, lead && i == 0, st, m);
} else {
ans += dfs(p - 1, limit && i == up, lead && i == 0, st | (1 << i), m);
}
}
if (!limit && !lead) {
dp[p][st] = ans;
}
return ans;
}
int calc(int x, int m) {
p = 0;
do {
a[++p] = x % 10;
x /= 10;
} while (x);
memset(dp, -1, sizeof(dp));
return dfs(p, 1, 1, 0, m);
}
void solve() {
int L, K;
cin >> L >> K;
int l, r;
l = L;
r = L + K;
for (int i = 10; i >= 0; --i) {
int ans = calc(r, i) - calc(l - 1, i);
if (ans) {
cout << i << " " << ans << endl;
break;
}
}
}
int main() {
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}