A. Not a Substring
题意
给出一段长度为 n 的仅由(
和)
组成的字符串,要求输出一段长度为 2*n 的不包含给定字串的字符串,其中()
要对应,比如说不能)(
思路
这题还是想了一会儿,最后发现其实只有()
的情况不能输出,其余情况可以按照以下规则输出:
- 如果给出的子串中有两个相同括号相连,比如说
((
或者))
,那只要连着输出()
就可以使最终结果不包含两个相同的括号相邻 - 如果给出的子串没有两个相同括号相连,那只要在输出时让相同括号相连就好了,输出 n 个
(
和 n 个)
即可
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
typedef pair<int, int> PII;
void solve()
{
string s;
cin >> s;
if (s == "()")
{
cout << "NO\n";
return;
}
cout << "YES\n";
bool flag1 = false, flag2 = false;
for (int i = 1; i < s.size(); i ++ )
if (s[i] == s[i - 1])
{
flag1 = true;
break;
}
if (flag1)
{
for (int i = 0; i < 2 * s.size(); i ++ )
{
if (i % 2 == 0) cout << "(";
else cout << ")";
}
cout << '\n';
}
else
{
for (int i = 0; i < s.size(); i ++ ) cout << "(";
for (int i = 0; i < s.size(); i ++ ) cout << ")";
cout << "\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}
B. Fancy Coins
题意
这个人要买 m 元钱的东西,只能付给商家 m 元不能多给
他现在有 a1
个面值为 1 元的普通硬币和无数个面值为 1 元的特殊硬币,还有ak
个面值为 k 元的普通硬币和无数个面值为 k 元的特殊硬币
现在问他需要付的最少的特殊硬币的数量是多少
思路
读题花了我好久啊读不懂题太emo了
一开始看题很容易想成先用普通硬币全付掉然后剩下的用特殊硬币来付,于是成功wa了一发…
要注意他想让特殊硬币的数量最少而不是面值最小,举个栗子如果用普通硬币付完之后还剩下20元需要付,此时k=7,那可以先付两个特殊硬币也就是14元,还剩下6元用6个面值为1元的特殊硬币付(?仔细思考一下是这样吗)显然不是,此时可以少付一枚面值为1的普通硬币,这样需要用特殊硬币来付的金额就变成了21元,只需要3枚特殊硬币即可
所以这一题首先判断一下能不能用普通硬币来付完所有的金额(需要注意并不是普通硬币的总金额达到了就可以付,要看看两种不同面值的普通硬币能不能组合为需要付款的金额),如果能付完那就不需要用特殊硬币直接输出0,如果不能就进入下一步
先用普通硬币付尽可能多的金额,剩下的钱再用特殊硬币中面值为 k 的付款,最后剩下小于 k 的金额没有付款,看看这个金额距离 k 还有多少,能不能用普通硬币组合而成(如果能用普通硬币组合,我们就可以少付这么多普通硬币,从而让最后剩余的金额变为 k ,直接付一枚特殊硬币),如果能的话直接在原答案基础上加1,不能就加上多出的那一部分(多出来的全部用面值为1的特殊硬币付)
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
typedef pair<int, int> PII;
bool check(i64 sum, i64 a1, i64 ak, i64 k)
{
if (sum > a1 + ak * k) return false;
if (ak * k >= sum) sum -= sum / k *k;
else sum -= ak * k;
if (sum <= a1) return true;
else return false;
}
void solve()
{
i64 m, k, a1, ak;
cin >> m >> k >> a1 >> ak;
if (check(m, a1, ak, k))
{
cout << 0 << '\n';
return;
}
else
{
i64 have;
if (m >= k * ak + a1) have = k * ak + a1;
else have = m / k * k + a1;
i64 sum = m - have;
i64 cnt = 0;
if (sum % k > 1 && check(k - sum % k, a1, ak, k)) cnt = sum / k + 1;
else
{
cnt = sum / k;
if (sum % k != 0) cnt += sum % k;
}
cout << cnt << '\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}
C. Game on Permutation
题意
如果点 i 和 j 满足 j < i
且 a[j] < a[i]
,则可以从 i 点移动到 j 点
问所有满足该条件的点的个数:该点前面的任何一个可以移动到的点,都不能移动到其他点
思路
遍历数组时记录下当前最小值 minn
和当前满足条件的点的最小值,之后的数一旦小于当前最小值,说明它不能移动,必然不可能是满足条件的点,如果不小于当前最小值但大于当前满足条件的点的最小值,说明它一定可以移动到满足条件的点,它本身也就不可能是满足条件的点(因为可以移动到的点还能移到其他点)
代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
int cnt = 0;
int minn = n + 1;
int minlose = n + 1;
for (int i = 0; i < n; i ++ )
{
bool res = true;
if (a[i] < minn) // 小于当前最小值必输
{
minn = a[i];
res = false;
}
else if (a[i] > minlose) // 大于当前稳赢的最小值必输
{
res = false;
}
if (res) // 当前点稳赢
{
cnt ++ ;
minlose = min(minlose, a[i]); // 更新当前稳赢最小值
}
}
cout << cnt << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
}