A. Three swimmers
题意:
给四个整数
p
,
a
,
b
,
c
p,a,b,c
p,a,b,c。其中
a
,
b
,
c
a,b,c
a,b,c分别表示三个游泳者到达泳池边的时间点,比如,第一个游泳者到达泳池边的时间就是
0
,
a
,
2
a
,
3
a
,
…
0,a,2a,3a,\dots
0,a,2a,3a,…。p表示的是一个人来到泳池边的时间点,问这个人在泳池边要等多久才能见到第一个到达泳池边的游泳者。
题解:
直接找
a
,
b
,
c
a,b,c
a,b,c的大于等于p的最小倍数即可。注意数据范围比较大,保守起见开了
u
n
s
i
g
n
e
d
l
o
n
g
l
o
n
g
unsigned\ long\ long
unsigned long long。
具体细节见代码:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
ll p, a, b, c;
cin >> p >> a >> b >> c;
ll newa = (p + a - 1) / a * a;
ll newb = (p + b - 1) / b * b;
ll newc = (p + c - 1) / c * c;
cout << min(newa, min(newb, newc)) - p << endl;
}
return 0;
}
B. Card Deck
题意:
给了我们一个长度为n的排列p,p的第一个元素是底,最后一个元素是顶,我们每次可以从顶取出一些元素放在一个新牌组上,原来在p中当顶的元素成为新牌组中的底,按这种方式取出所有p的元素,让我们找出一个排列使得
∑
i
=
1
n
n
n
−
i
⋅
p
i
\sum_{i=1}^n n^{n-i}·p_i
∑i=1nnn−i⋅pi的值最大。
题解:
看起来比较棘手,不过我们分析题目所给的样例能够很快发现,其实就是从后往前找到当前剩余元素中最大的数的位置
i
i
i,然后把从
i
i
i到结尾的所有元素取出放入新牌组即可。每次按这种方式取,直到取完。
具体实现见代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int p[MAXN];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
int n;
int maxx = -1, id = 0;
set<int> vis;
vector<int> ans;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i];
if (p[i] > maxx) {
maxx = p[i];
id = i;
}
}
for (int i = n - 1; i >= 0; i--) {
ans.emplace_back(p[i]); // 从顶依次加入元素
vis.insert(p[i]); // 判断元素是否被取过
if (p[i] == maxx) { // 如果当前元素是最大值,倒序输出
int len = ans.size();
for (int j = len - 1; j >= 0; j--) {
cout << ans[j] << " ";
}
ans.clear();
while (vis.count(maxx)) { // 找到当前剩余元素中的最大值
maxx--;
}
}
}
cout << endl;
}
return 0;
}
C. Maximum width
题意:
给我们一个长度为n的字符串S和一个长度为m的字符串T,让我们找到一个长度为m的严格上升的序列p,使得p中元素在S串中对应的字符串正好是T串,同时定义p序列的宽度是p中元素
p
i
+
1
−
p
i
p_{i+1} - p_i
pi+1−pi的最大值,问我们这个宽度最大可以是多少?
题解:
这道题目,由于求的是相邻字符对应位置的差值的最大值,那么为了使这个差值最大,我们容易想到相邻字符一个取最左的坐标,一个取最右的坐标,因此我们可以对T串前后扫两边,从前扫,每次找到当前T串字符在S串的最左的位置坐标;从后扫,每次找到当前T串字符在S串的最右的位置坐标。最后,扫描一遍T串,找到相邻字符的坐标差值最大值。
具体细节见代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
ll nowr[MAXN], nowl[MAXN];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int m, n;
cin >> n >> m;
string s, t;
cin >> s >> t;
ll sleft = 0;
for (int i = 0; i < m; i++) {
while (s[sleft] != t[i] && sleft <= n - 1) { // 找到当前t[i]在s串中的最左坐标
sleft += 1;
}
nowl[i] = sleft++;
}
ll sright = n - 1;
for (int i = m - 1; i >= 0 && sright >= 0; i--) { // 找到当前t[i]在s串中的最右坐标
while (s[sright] != t[i] && sright >= 0) {
sright -= 1;
}
nowr[i] = sright--;
}
ll ans = 0;
for (int i = 1; i < m; i++) {
ans = max(ans, nowr[i] - nowl[i - 1]);
}
cout << ans << endl;
return 0;
}
D. Genius’s Gambit
这题FST比例就离谱。感觉大部分都是错在一些特判上。
题意:
给我们3个整数
a
,
b
,
k
a,b,k
a,b,k,让我们判断能不能构造出两个二进制数
x
x
x和
y
y
y,满足:
- x ≥ y x≥y x≥y
- x x x和 y y y中都有 a a a个0和 b b b个1
- x − y x-y x−y这个二进制数中有 k k k个1
题解:
经过手推几个样例,能够发现当
k
>
a
+
b
−
2
k>a+b-2
k>a+b−2时不能构造这样的二进制数。不过,这样其实是不对的,当样例是0 1 0的时候,我们可以构造
x
=
1
y
=
1
x=1\ y=1
x=1 y=1这样两个二进制数,因此我们要对
b
=
1
,
k
=
0
b=1,k=0
b=1,k=0的时候进行特判。我这里一般的构造方法就是,根据
a
a
a和
k
k
k的大小关系,分别进行两种不同的构造。
当 a ≥ k a≥k a≥k时,对于 x 和 y x和y x和y,先以 b − 1 b-1 b−1个1开头。然后由于最后要有k个1,因此,在 x x x中,我以倒数第 k k k个位置作为分界线,给倒数第 k k k个位置设为1,其他位置设为0;在 y y y中,我把最后一个位置设为1,其他剩余位置设为0,这样 x − y x-y x−y就一定有k个1,且满足其他条件。
当 a < k a<k a<k时,我把 x x x的最后 a a a个位置设为0,其他位置都设为1。而 y y y中,与x不同之处就在就在 a + b − k a+b-k a+b−k这个位置,在 x x x中是1,但是在 y y y中我设置为0。
按照以上方式写出的构造程序,看起来是对的,不过,少了 a = 0 a = 0 a=0时的特判。我们发现当 a = 0 , k = 0 a=0,k=0 a=0,k=0时,其实是可以构造出全部是1的两个二进制数。
具体细节见代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int a, b, k;
cin >> a >> b >> k;
if (b == 1) { // 特判b = 1
if (k == 0) {
cout << "Yes" << endl;
cout << 1;
for (int i = 1; i <= a; ++i) {
cout << 0;
}
cout << endl;
cout << 1;
for (int i = 1; i <= a; ++i) {
cout << 0;
}
cout << endl;
}
else {
cout << "No" << endl;
}
return 0;
}
if (a == 0) { // 特判a = 0
if (k == 0) {
cout << "Yes" << endl;
for (int i = 1; i <= b; ++i) {
cout << 1;
}
cout << endl;
for (int i = 1; i <= b; ++i) {
cout << 1;
}
cout << endl;
}
else {
cout << "No" << endl;
}
return 0;
}
if (k > a + b - 2) {
cout << "No" << endl;
}
else if (a >= k) {
cout << "Yes" << endl;
for (int i = 1; i < b; i++) {
cout << 1;
}
for (int i = 1; i <= a - k; i++) {
cout << 0;
}
cout << 1;
for (int i = 1; i <= k; i++) {
cout << 0;
}
cout << endl;
for (int i = 1; i < b; i++) {
cout << 1;
}
for (int i = 1; i <= a; i++) {
cout << 0;
}
cout << 1 << endl;
}
else {
cout << "Yes" << endl;
for (int i = 1; i < a + b - k; i++) {
cout << 1;
}
cout << 1;
for (int i = 1; i <= k - a; i++) {
cout << 1;
}
for (int i = 1; i <= a; i++) {
cout << 0;
}
cout << endl;
for (int i = 1; i < a + b - k; i++) {
cout << 1;
}
cout << 0;
for (int i = 1; i <= k - a; i++) {
cout << 1;
}
for (int i = 1; i < a; i++) {
cout << 0;
}
cout << 1 << endl;
}
return 0;
}