A.Neverending competitions(Codeforces 765A)
题解:直接判断坐飞机的次数是奇数还是偶数就可以了。
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
char h[100];
int n;
int main() {
scanf("%d", &n);
scanf("%s", h + 1);
for (int i = 1; i <= n; i ++)
scanf("%s", h + 1);
if (n % 2 == 0) printf("home\n"); else
printf("contest\n");
}
B.Code obfuscation(Codeforces 765B)
题解:根据题意,记录做到第当前位置最大的字母是什么,判断当前位置是否和法,然后更新最大的字母。
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 505;
char s[MAXN];
int main() {
scanf("%s", s + 1);
int len = strlen(s + 1), now = -1;
for (int i = 1; i <= len; i ++) {
if (s[i] - 'a' > now + 1) {
printf("NO\n");
return 0;
}
now = max(s[i] - 'a', now);
}
printf("YES\n");
}
C.Table Tennis Game 2(Codeforces 765C)
题解:首先判断是否进行了至少一盘的游戏。然后a/n+b/n就是进行盘数最多的答案。但是有一种特殊的不合法的情况就是,a/n==0且b%n!=0时,肯定是不合法的,因为a没有赢过,一直是b赢,但是b%n!=0又证明b输过,矛盾。b/n==0且a%n!=0同理。
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
int n, a, b;
scanf("%d%d%d", &n, &a, &b);
int ans = a / n + b / n;
if (a / n == 0 && b % n != 0 || b / n == 0 && a % n != 0) ans = 0;
if (ans == 0) printf("-1\n"); else printf("%d\n", ans);
}
D. Artsem and Saunders(Codeforces 765D)
题解:设有上下两排点,各有m个和n个,对于下面的点i,我们在上面设一个点j,强行令h[j]=f[i],那么令g[i]=h[j]即可,不合法情况就是f[f[i]]!=f[i]。
#include <bits/stdc++.h>
#define fe first
#define se second
using namespace std;
const int maxn = 100005;
int f[maxn],g[maxn],h[maxn],vis[maxn],n,m;
int main()
{
scanf("%d", &n);
for(int i = 1;i <= n;i ++) scanf("%d", &f[i]);
for(int i = 1;i <= n;i ++)
if (f[f[i]] != f[i]) {printf("-1\n");return 0;}
for(int i = 1;i <= n;i ++)
{
if (!vis[f[i]]) vis[f[i]] = ++ m,h[m] = f[i];
g[i] = vis[f[i]];
}
printf("%d\n", m);
for(int i = 1;i <= n;i ++) printf("%d%c", g[i],i == n ? '\n' : ' ');
for(int i = 1;i <= m;i ++) printf("%d%c", h[i],i == m ? '\n' : ' ');
return 0;
}
E. Tree Folding(Codeforces 765E)
题解:首先假如有解,最后剩下的一条链肯定是直径,然后再把直径不断的对折。也就是说,无论怎么操作,只要能成功答案就一定是一样的。我们可以先随便设一个节点为根。从底向上合并上来。对于一个非根节点,儿子的深度一定要相同才能合并。对于根节点则可以存在两种什么。当合并时存在非根的不合法点是,直接把这个点设为根再跑一遍找答案,如果都不可以答案就是-1。否则令找到的链长度不断除二直到除不尽。
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
const int MAXN = 2e5 + 5;
int n, root;
int tot, Last[MAXN], Next[MAXN * 2], Go[MAXN * 2];
void link(int u, int v) {
Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;
}
int dfs(int now, int pre) {
set<int> q;
for (int p = Last[now]; p; p = Next[p]) {
int v = Go[p];
if (v == pre) continue;
int tmp = dfs(v, now);
if (tmp == -1) return -1;
q.insert(tmp + 1);
}
if (q.size() == 0) return 0;
if (q.size() == 1) return *q.begin();
if (q.size() == 2 && !pre) return *q.begin() + *q.rbegin();
root = now;
return -1;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
link(u, v), link(v, u);
}
int ans = dfs(1, 0);
if (ans == -1 && root) ans = dfs(root, 0);
for (; (ans & 1) == 0; ans /= 2);
printf("%d\n", ans);
}
F. Souvenirs(Codeforces 765F)
题解:把询问离线,考虑把数一个个加入序列中更新答案。假设从右往左加数,当前加到了第l个数,令b[i]=min{|a[j]-a[i]|j>i,i>l},用线段树维护b数组。显然b数组从左到右是单调不下降的。那么对于每个询问就是要求各前缀最小值,根据这个我们发现我们不需要把全部的b求出来。有些不必要的更新,即假设对于j
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
const int MAXN = 1e5 + 5, MAXM = 3e5 + 5;
const int Inf = 1e9;
struct Query {
int l, r, id;
} que[MAXM];
struct Node {
int mn;
set<int> d;
} tr[MAXN * 4];
int n, m, a[MAXN], ans[MAXM];
bool cmp(Query a, Query b) {
return a.l > b.l;
}
void build(int now, int l, int r) {
tr[now].mn = Inf;
for (int i = l; i <= r; i ++) tr[now].d.insert(a[i]);
if (l == r) return;
int mid = (l + r) >> 1;
build(now * 2, l, mid), build(now * 2 + 1, mid + 1, r);
}
int query(int now, int l, int r, int lx, int rx) {
if (rx < l || lx > r) return Inf;
if (l >= lx && r <= rx) return tr[now].mn;
int mid = (l + r) >> 1;
return min(query(now * 2, l, mid, lx, rx), query(now * 2 + 1, mid + 1, r, lx, rx));
}
void modify(int now, int l, int r, int lx, int rx, int num, int &mn) {
if (rx < l || lx > r) return;
if (l == r) {
tr[now].mn = min(tr[now].mn, abs(a[l] - num));
mn = min(mn, tr[now].mn);
return;
}
set<int> :: iterator p = tr[now].d.lower_bound(num);
if ((p == tr[now].d.end() || (*p - num >= mn)) && (p == tr[now].d.begin() || (num - *(-- p) >= mn))) {
mn = min(mn, query(now, l, r, lx, rx));
return;
}
int mid = (l + r) >> 1;
modify(now * 2, l, mid, lx, rx, num, mn), modify(now * 2 + 1, mid + 1, r, lx, rx, num, mn);
tr[now].mn = min(tr[now * 2].mn, tr[now * 2 + 1].mn);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
scanf("%d", &m);
for (int i = 1; i <= m; i ++) {
scanf("%d%d", &que[i].l, &que[i].r);
que[i].id = i;
}
sort(que + 1, que + m + 1, cmp);
build(1, 1, n);
for (int i = 1, lst = n, tmp; i <= m; i ++) {
for (;lst >= que[i].l; lst --)
modify(1, 1, n, lst + 1, n, a[lst], tmp = Inf);
ans[que[i].id] = query(1, 1, n, que[i].l, que[i].r);
}
for (int i = 1; i <= m; i ++) printf("%d\n", ans[i]);
}