比赛链接(可赛后补题):https://www.starrycoding.com/contest/11
A. a+b(easy)
由于 a a a和 b b b都是0到9之间的整数,则表达式的长度必定为3,所以直接将 a a a和 b b b提取出来计算即可。
代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
string s;cin >> s;
cout << (s[0] - '0') + (s[2] - '0') << '\n';
}
int main()
{
int t;cin >> t;
while(t--)solve();
}
B. a+b(hard)
遍历表达式字符串,将 a a a和 b b b提取出来进行计算即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
string s;cin >> s;
int a = 0,b = 0;
bool flag = true;
for(auto &i : s)
{
if(i == '+')flag = false;
else
{
if(flag)a = a * 10 + (i - '0');
else b = b * 10 + (i - '0');
}
}
cout << a + b << '\n';
}
signed main()
{
int t;cin >> t;
while(t--)solve();
}
C. 最近不存在数字
将数组 a a a中所有数字存入 s e t set set中(当然用 m a p map map等其他数据结构也可以),方便后续判断存在性。
枚举与 b b b的距离 i i i,先判断较小的 b − i b-i b−i,再判断 b + i b+i b+i,若不存在于 a a a中就直接返回结果。
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 9;
ll a[N];
void solve()
{
ll n, b;
cin >> n >> b;
set<ll> st;
for (int i = 1; i <= n; ++i)
{
ll x;
cin >> x;
st.insert(x);
}
for (int i = 0; i <= 1e5; ++i)
{
if (!st.count(b - i))
{
cout << b - i << '\n';
return;
}
if (!st.count(b + i))
{
cout << b + i << '\n';
return;
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
D. 数字根
我们将1~36写出来,
$
\begin{bmatrix}
1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9\
10 & 11 & 12 & 13 & 14 & 15 & 16 & 17 & 18\
19 & 20 & 21 & 22 & 23 & 24 & 25 & 26 & 27\
28 & 29 & 30 & 31 & 32 & 33 & 34 & 35 & 36\
\cdots \
\end{bmatrix}
$
我们发现同一列中的数字元素数字根都相同,所以我们推测数字根出现的规律大致是以9为一个周期递推,而事实也正是如此。所以我们要找第
k
k
k个数字根为
x
x
x的数字,也就是在上述矩阵中第
k
k
k行,第
x
x
x列的元素,所以答案为
(
k
−
1
)
×
9
+
x
(k - 1) \times 9 + x
(k−1)×9+x。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int k,x;cin >> k >> x;
cout << (k - 1) * 9 + x << '\n';
}
signed main()
{
int t;cin >> t;
while(t--)solve();
}
E.再短一点
思路
长度为 m m m的二进制字符串 T T T是幸运的,当且仅当 m = 1 m = 1 m=1或( 1 < m 1 \lt m 1<m和 S [ m ] ≠ S [ m − 1 ] S[m] \neq S[m - 1] S[m]=S[m−1])。
- 在 S [ m − 1 ] = S [ m ] S[m - 1] = S[m] S[m−1]=S[m]的情况下:我们永远不能删除最后两个字符,因为它们将始终保持相等。所以 S S S 不是幸运的。
- 在 S [ m − 1 ] ≠ S [ m ] S[m - 1] \neq S[m] S[m−1]=S[m]的情况下:如果 m = 2 m = 2 m=2,我们可以通过一次操作达到我们的目标。否则,假设最后一个字符为0。现在最后三个字符不是010就是110。在第一种情况下,对 [ S m − 2 , S m − 1 ] [S_{m-2},S_{m-1}] [Sm−2,Sm−1]执行操作,在第二种情况下,对 [ S m − 1 , S m ] [S_{m-1},S_m] [Sm−1,Sm] 执行操作。然后最后两个字符将是10,我们可以在新的字符串上继续这个算法,直到我们得到 m = 1 m = 1 m=1。
长度为 1 1 1的幸运的子字符串的个数等于 n n n。为了计算更长的子字符串的个数,我们可以将索引 2 2 2中的 r r r固定为 n n n。如果 S [ r ] ≠ S [ r − 1 ] S[r] \neq S[r - 1] S[r]=S[r−1]成立,我们应该在答案上加上 r − 1 r - 1 r−1。
复杂性: O ( n ) \mathcal{O}(n) O(n)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
void solve()
{
int n; cin >> n;
ll ans = n;
string s; cin >> s;
for(int i = 1; i < n; ++i)
{
if(s[i] != s[i - 1]) ans += i;
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while(_ --)solve();
return 0;
}
F.更短一点
思路
已知我们无法对非降序的字符串进行操作。
操作的条件:前1后0。所以猜想:对于一串以1开头,以0结尾的子串都可以被擦除至剩一个0。
证明:
对于一串以1开头的字符串,从前往后删0,我们总能得到一串不包含0的字符串,这很容易。现在保留末尾的0,再从后往前删掉所有的1。显然是可取的。
于是我们得到结论,对于一串以1开头,以0结尾的子串都可以被擦除至剩一个0。而由于我们无法对非降序的字符串进行操作,所以答案的构成我们可以视作:
00 … 00 ⏟ x S 11 … 11 ⏟ y \underbrace{00 \ldots 00}_{x} \space S \space \underbrace{11 \ldots 11}_{y} x 00…00 S y 11…11
其中 S S S为一串以1开头,以0结尾的子串。必然是这样的,如果在最前面加上一个1,那么不妨把中间子串的左边界扩至开头来保持结构;在末尾加0也是同理。
于是我们只要找第一个1,再找末尾一个0,将这两个位置及其中间的字符都替换为0即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
void solve()
{
int n; cin >> n;
string s; cin >> s;
int l = -1, r = -1;
int flag = 1;
for(int i = 0; i < n; ++i)
{
if(s[i] == '1' && flag)
{
l = i;
flag = 0;
}
if(s[i] == '0' && !flag)
{
r = i;
}
}
if(l != -1 && r != -1)
{
for(int i = 0; i < l; ++i) cout << s[i];
for(int i = r; i < n; ++i) cout << s[i];
cout << '\n';
}
else cout << s << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while(_ --)solve();
return 0;
}