原题链接:Codeforces Round #835 (Div. 4)
目录
A. Medium Number
题意:输出三个数的中间值。
思路: 输入a[1]~a[3] sort一下输出a[2]。
void solve() {
cin >> a[1] >> a[2] >> a[3];
sort(a + 1 , a + 4);
cout << a[2] << endl;
}
B. Atilla's Favorite Problem
题意:字符 a∼z 编号为 1∼26 ,输出字符串中编号最大的字符对应的数值。
思路:输入字符串sort一下输出最大的ascall码值-96。
void solve() {
int n;
string s;
cin >> n >> s;
sort(s.begin(),s.end());
cout << s[n-1]-96 << endl;
}
C. Advantage
题意:找每个数和最大数的差,若该数为最大数,则输出其与次大数的差。
思路:将数据存入两个数组中,一个用来排序,一个用来输出。
void solve() {
int n;
cin >> n;
FOR(1, n) {
cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
FOR(1, n) {
int x = a[i] == b[n] ? b[n] - b[n - 1] : a[i] - b[n];
cout << x << " \n"[i == n];
}
}
D. Challenging Valleys
题意:找山谷,即上升后就不能再下降。
思路:标记是否已经上升了,若上升还下降了则输出NO。
void solve() {
bool flag = false;
int n;
cin >> n;
FOR(1, n) cin >> a[i];
FOR(2, n) {
if (a[i - 1] < a[i]) flag=true;
if (a[i - 1] > a[i] && flag) {
no;
return;
}
}
yes;
}
E. Binary Inversions
题意:给定 01 串,求最多反转其中一个位置的前提下,最大的逆序对数。
思路:我们可以发现总逆序对数就是每个0前面的出现1的次数之和,所以要让答案最大化,我们可以将最前面的0变成1,这样0变1对答案做出的贡献最大,因为将后面的0变1,会使后面的每个0前面1的数量变少。或者将最后面的1变成0,这样1变0对答案做出的贡献最大,因为将前面的1变0,变成0前面的1的个数,肯定没后面的1变成0,0前面1的个数多。最后还要比较不变的情况,三者取max即可。
void solve() {
int n, f = 0, cnt = 0, ans = 0, ans2 = 0, ans3 = 0;
cin >> n;
FOR(1, n) {
cin >> a[i];
b[i] = a[i];
c[i] = a[i];
if (!a[i] && !f) { //将最前面的0变成1
a[i] = 1;
f = 1;
}
}
ROF(n, 1) { //将最后面的1变成0
if (b[i]) {
b[i] = 0;
break;
}
}
FOR(1, n) {//0变1的逆序对数
if (a[i] == 0)
ans += cnt;
else
cnt += a[i];
}
cnt = 0;
FOR(1, n) {//1变0的逆序对数
if (b[i] == 0)
ans2 += cnt;
else
cnt += b[i];
}
cnt = 0;
FOR(1, n) {//不变的逆序对数
if (c[i] == 0)
ans3 += cnt;
else
cnt += c[i];
}
cout << max(ans, max(ans2, ans3)) << endl;//三者取max
}
F. Quests
题意:有 n 个任务,每个任务做完会获得 ai 的奖励,任务做完会有 x 天的 cd ,必须在 x+1 天才能继续完成这个任务。给定参数 c,d ,请问在 d 天获得至少 c 的奖励的最大cd是多少。
思路:首先考虑特殊情况,若最大的ai*d小于c说明无解。然后我们将数组a sort一下,用ans数组来表示前缀和,如果ans[min(n,d)]>=c,则无论x多大都有解。最后我们二分答案x,对于check函数,我们将(x+1)天作为一个周期,每个周期我们最多可以获得ans[min(x+1,n)]的奖励,别忘了处理d溢出的部分。
bool check(int x) {
int sum = 0;
sum += (d / (x + 1)) * ans[min(x + 1, n)];
sum += ans[min(n, (d % (x + 1)))];
if (sum >= c) return 1;
return 0;
}
bool cmp(int x, int y) {
return x > y;
}
void solve() {
int maxx = -inf;
cin >> n >> c >> d;
int l = 0, r = d + 1;
FOR(1, n) {
cin >> a[i];
maxx = max(maxx, a[i]);
}
if (maxx * d < c) {
cout << "Impossible" << endl;
return;
}
sort(a + 1, a + n + 1, cmp);
FOR(1, n) ans[i] = ans[i - 1] + a[i];
if (ans[min(n, d)] >= c) {
cout << "Infinity" << endl;
return;
}
while (l < r) {
int mid = (l + r) / 2;
if (check(mid))
l = mid + 1;
else
r = mid;
}
cout << l - 1 << endl;
}
G. SlavicG's Favorite Problem
题意:给定一棵带边权的树,给定起点 a 和终点 b ,从 a 出发,刚开始的分数为 0 ,每走过一条边会使分数异或上这个值,要求最后走到 b 的分数为 0 ,并可以进行任意一次传送,求能否满足要求。
思路:双向搜索即可,若a点到某一点的值与b点到某一点的值相等,那么就可以从传送到这一点,两者的异或值肯定为0。
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa, int cur) {
mp[cur] = 1;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == fa || j == y) continue;
dfs(j, u, cur ^ w[i]);
}
}
void dfs2(int u, int fa, int cur) {
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == fa) continue;
dfs2(j, u, cur ^ w[i]);
if (flag) return;
if (mp[cur ^ w[i]]) flag = true;
}
}
void solve() {
mem(h, -1);
mp.clear();
idx = 0;
cin >> n >> x >> y;
FOR(1, n - 1) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
flag = false;
dfs(x, 0, 0);
dfs2(y, 0, 0);
if (flag)
yes;
else
no;
}