旅行传送门
A. Regular Bracket Sequences
题意:给你一个整数 n n n ,构造并打印长度为 2 n 2n 2n 的 n n n 个不同的合法括号序列。
题目分析:模拟,不妨设最初的括号序列为 ( ( ( ⏟ n ⋯ ) ) ) ⏟ n \underbrace{(((}_{n} \cdots \underbrace{)))}_{n} n (((⋯n ))) ,每次从中取出一对合法括号放外边即可。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void solve()
{
int n = read();
down(k, n, 1)
{
rep(i, 1, k) printf("(");
rep(i, 1, k) printf(")");
rep(j, 1, n - k) printf("()");
puts("");
}
}
int main(int argc, char const *argv[])
{
int T = read();
while (T--)
solve();
return 0;
}
B. Combinatorics Homework
题意:给你四个整数值 a a a 、 b b b 、 c c c 和 m m m 。
判断是否存在包含以下内容的字符串:
- a a a 个字母 A A A
- b b b 个字母 B B B
- c c c 个字母 C C C
- 正好含有 m m m 对相邻的相等字母(即 s [ i ] = s [ i + 1 ] s[i] = s[i+1] s[i]=s[i+1] )。
题目分析:不妨假设 a ≤ b ≤ c a \leq b \leq c a≤b≤c ,先考虑相邻相等字母的上下限:
- 上限: A A A ⏟ a ⋯ B B B B ⏟ b ⋯ C C C C C ⏟ c \underbrace{AAA}_{a} \cdots \underbrace{BBBB}_{b} \cdots \underbrace{CCCCC}_{c} a AAA⋯b BBBB⋯c CCCCC ,即 ( a − 1 ) + ( b − 1 ) + ( c − 1 ) (a-1)+(b-1)+(c-1) (a−1)+(b−1)+(c−1)
- 下限: C A C A ⏟ a 个 C ⋯ C B C B C B ⏟ b 个 C ⋯ C C C C C \underbrace{CACA}_{a个C} \cdots \underbrace{CBCBCB}_{b个C} \cdots CCCCC a个C CACA⋯b个C CBCBCB⋯CCCCC ,即 c − ( a + b ) − 1 c - (a+b) - 1 c−(a+b)−1
可以证明,若 m i n ≤ m ≤ m a x min \leq m \leq max min≤m≤max ,则这样的序列一定存在。
- m i n + 1 min +1 min+1 : A C A C A ⋯ C A ⏟ a − 1 个 C C B C B C B ⏟ b 个 C ⋯ C C C C C + C \underbrace{ACACA \cdots CA}_{a-1个C} \underbrace{CBCBCB}_{b个C} \cdots CCCCC+C a−1个C ACACA⋯CAb个C CBCBCB⋯CCCCC+C
- m i n + 2 min +2 min+2 : C A C A ⋯ C A A ⏟ a − 1 个 C C B C B C B ⏟ b 个 C ⋯ C C C C C + C \underbrace{CACA \cdots CAA}_{a-1个C} \underbrace{CBCBCB}_{b个C} \cdots CCCCC+C a−1个C CACA⋯CAAb个C CBCBCB⋯CCCCC+C
在 m i n min min 的基础上每多出一对邻相等字母,就把字符串的头字母放到该字母最后一次出现的位置之后。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
bool solve()
{
int a = read(), b = read(), c = read(), m = read();
if (c < a)
std::swap(a, c);
if (c < b)
std::swap(b, c);
int mx = a + b + c - 3, mn = std::max(c - (a + b) - 1, 0);
return (mn <= m && m <= mx) ? true : false;
}
int main(int argc, char const *argv[])
{
int T = read();
while (T--)
puts(solve() ? "YES" : "NO");
return 0;
}
C. Slay the Dragon
题意:很久很久以前,巨龙突然出现
你有一支含 n n n 位勇者的小队,现在有 m m m 条恶龙,第 i i i 条的防御为 x i x_i xi ,攻击力为 y i y_i yi 。对每条龙,你可以选出一名能力值 a i ≥ x i a_i \geq x_i ai≥xi 的勇者诛戮恶龙,其余勇者留下来防守,且防守的勇者们能力值总和 s u m ≥ y i sum \geq y_i sum≥yi 。
同时,你可以花费 1 1 1 点 c o s t cost cost 将任意勇者的能力值提升 1 1 1 点,此操作可以进行任意次。
问击败第 i i i 条龙的最小花费是多少(对战每条龙时所有勇者的能力值重置)。
题目分析:采取贪心策略,找到序列中首次出现的 ≥ \geq ≥ 和 ≤ x i \leq x_i ≤xi 的值 a i a_i ai ,然后计算相应花费输出较小的即可。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
using ll = long long;
using namespace std;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline bool cmp(ll a, ll b) { return a > b; }
int main(int argc, char const *argv[])
{
int n = read();
ll sum = 0;
vector<ll> a(n + 1), b(n + 1);
rep(i, 1, n) sum += (a[i] = b[i] = read());
sort(a.begin() + 1, a.begin() + n + 1);
sort(b.begin() + 1, b.begin() + n + 1, cmp);
int m = read();
while (m--)
{
ll x = read(), y = read();
int pos1 = lower_bound(a.begin() + 1, a.begin() + n + 1, x) - a.begin();
int pos2 = lower_bound(b.begin() + 1, b.begin() + n + 1, x, greater<ll>()) - b.begin();
if (pos1 > n)
pos1 = n;
if (pos2 > n)
pos2 = n;
ll ans1 = 0, ans2 = 0;
if (x > a[pos1])
ans1 += x - a[pos1];
if (y > sum - a[pos1])
ans1 += y - (sum - a[pos1]);
if (x > b[pos2])
ans2 += x - b[pos2];
if (y > sum - b[pos2])
ans2 += y - (sum - b[pos2]);
printf("%lld\n", min(ans1, ans2));
}
return 0;
}
D. The Strongest Build
题意:给你 n n n 个装备槽,每个装备槽有 c c c 件装备可以挑选,每件装备的属性值为 a i , j a_{i,j} ai,j ,现有 m m m 种不合法的方案数,求在此条件下使得属性值最大的组合方案。
题目分析:一开始用 d f s dfs dfs 暴搜结果 M L E MLE MLE 了。这里给出一种贪心的策略,优先用更好的装备,第 i i i 个装备槽只考虑能使方案合法的最好的第 j j j 个装备,每次从优先队列中取出当前最优方案,如果这个方案已经被 b a n ban ban 了,就将其分成 n n n 个后继方案(一个方案的后继就是对于当前组合里的某个槽,用刚好差一档的装备换上去),但分出的后继方案可能会有重复的,因此我们选择用 s e t set set 去重。由于优先队列采取的是大根堆,所以这样的做法一定能得到最优解。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i < (y); i++)
#define down(i, x, y) for (register int i = (x); i > (y); i--)
#define piv std::pair<int, std::vector<int>>
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
std::vector<int> v, g;
std::map<std::vector<int>, int> mp;
std::priority_queue<piv> q;
std::vector<std::vector<int>> f;
std::set<std::vector<int>> s;
int main(int argc, char const *argv[])
{
int n = read(), sum = 0;
rep(i, 0, n)
{
int c = read();
v.push_back(c);
g.clear();
rep(j, 0, c)
{
int k = read();
g.push_back(k);
}
f.push_back(g);
sum += g[c - 1];
}
q.push(std::make_pair(sum, v));
int m = read();
rep(i, 0, m)
{
g.clear();
rep(j, 0, n)
{
int k = read();
g.push_back(k);
}
++mp[g];
}
while (!q.empty())
{
piv ans = q.top();
q.pop();
sum = ans.first;
g = ans.second;
if (mp[g])
{
rep(i, 0, n)
{
if (g[i] <= 1)
continue;
int cur = f[i][g[i] - 1];
--g[i];
int nxt = f[i][g[i] - 1];
if (!s.count(g))
{
q.push(std::make_pair(sum - cur + nxt, g));
s.insert(g);
}
++g[i];
}
continue;
}
for (auto x : g)
printf("%d ", x);
puts("");
break;
}
return 0;
}
// 关于dfs:它死了
// #include <bits/stdc++.h>
// #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
// #define down(i, x, y) for (register int i = (x); i >= (y); i--)
// #define pii pair<int, int>
// using namespace std;
// char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
// inline int read()
// {
// int x = 0, f = 1;
// char ch = getchar();
// while (!isdigit(ch))
// {
// if (ch == '-')
// f = -1;
// ch = getchar();
// }
// while (isdigit(ch))
// {
// x = x * 10 + ch - '0';
// ch = getchar();
// }
// return x * f;
// }
// inline char qrc()
// {
// char c;
// while (!isdigit(c = getchar()))
// ;
// return c;
// }
// int n, ans;
// map<vector<int>, int> mp;
// vector<int> output;
// vector<pii> a[11];
// void dfs(int id, vector<int> v)
// {
// if (v.size() == n)
// {
// if (mp[v])
// return;
// int ans = 0;
// rep(i, 1, n)
// ans += a[i][v[i - 1] - 1].second;
// if (ans > ans)
// ans = ans, output = v;
// return;
// }
// for (auto x : a[id])
// {
// v.push_back(x.first);
// dfs(id + 1, v);
// v.pop_back();
// }
// }
// int main(int argc, char const *argv[])
// {
// n = read();
// rep(i, 1, n)
// {
// int c = read();
// rep(j, 1, c)
// {
// int k = read();
// a[i].push_back(make_pair(j, k));
// }
// }
// int m = read();
// rep(i, 1, m)
// {
// vector<int> v;
// rep(j, 1, n)
// {
// int k = read();
// v.push_back(k);
// }
// ++mp[v];
// }
// vector<int> v;
// dfs(1, v);
// for (auto x : output)
// printf("%d ", x);
// puts("");
// return 0;
// }