2021牛客寒假算法基础集训营3
2021牛客寒假算法基础集训营3
A 模数的世界
a == b == 0直接是0 0 0
其他的就构造 p - 1,
x = a + p(p - a - 1) = (p - 1)(p - a), y = (p - 1)(p - b)
但是可能存在 gcd(p - a, p - b) != 1, 导致构造 p - 1 失败,
那就让 x 一直 += p * (p - 1) 呗, 知道构造出 p - 1
int main() {
IOS;
for (cin >> _; _; --_) {
ll a, b, p; cin >> a >> b >> p;
if (a == 0 && b == 0) { cout << "0 0 0\n"; continue; }
a += p * (p - a - 1), b += p * (p - b - 1);
while (__gcd(a, b) % p != p - 1) a += p * (p - 1);
cout << p - 1 << ' ' << a << ' ' << b << '\n';
}
return 0;
}
B 内卷
贪心就行, 先全部都是最低级E, 不断提高当前分数最低的那个人的分数等级就好了, 就几行, 为啥这么少人过啊
struct { int a[5], deg; } a[N];
int main() {
IOS; cin >> n >> k; multimap<int, int> st;
rep (i, 1, n) per (j, 4, 0) cin >> a[i].a[j];
rep (i ,1, n) st.insert({a[i].a[0], i});
m = st.rbegin()->first - st.begin()->first;
while (1) {
auto it = st.begin(); st.erase(it);
int x = it->second; ++a[x].deg;
if (a[x].deg == 4) { if (k) --k; else break; }
else if (a[x].deg > 4) break;
st.insert({a[x].a[a[x].deg], x});
umin(m, st.rbegin()->first - st.begin()->first);
}
cout << m;
return 0;
}
C 重力坠击
数据范围很小, 爆搜
struct node { int x, y, r; }e[N];
void dfs(int now) {
if(now == k) {
memset(v, 0, sizeof(v));
int res = 0;
rep (i, 1, n) rep (j, 1, k)
if (sqr(a[j] - e[i].x) + sqr(b[j] - e[i].y)
<= sqr(r + e[i].r) && v[i] == 0) ++res, v[i] = 1;
umax(ans, res);
return;
}
rep (i, -7, 7) rep (j, -7, 7) {
a[now + 1] = i, b[now + 1] = j;
dfs(now + 1);
}
}
int main() {
IOS; cin >> n >> k >> r;
rep (i, 1, n) cin >> e[i].x >> e[i].y >> e[i].r;
dfs(0);
cout << ans << "\n";
return 0;
}
D Happy New Year!
int main() {
IOS; cin >> n;
if (n < 2030) cout << 2030 + (n % 10 - 1);
else cout << 2102;
return 0;
}
E 买礼物
最大值线段树, 维护出现上一个a[i]的位置的最大值
struct BIT {
struct node { int l, r, tag; } tr[N << 2];
void push_up(int rt) { tr[rt].tag = max(tr[rt << 1].tag, tr[rt << 1 | 1].tag); }
void build(int rt, int l, int r, int pre[]) {
tr[rt] = { l, r, 0 };
if (l == r) { tr[rt].tag = pre[l]; return; };
int mid = l + r >> 1;
build(rt << 1, l, mid, pre);
build(rt << 1 | 1, mid + 1, r, pre);
push_up(rt);
}
void change(int rt, int d, int k) {
if (tr[rt].l == tr[rt].r && tr[rt].l == d) { tr[rt].tag = k; return; }
int mid = tr[rt].l + tr[rt].r >> 1;
if (d <= mid) change(rt << 1, d, k);
if (d > mid) change(rt << 1 | 1, d, k);
push_up(rt);
}
int ask(int rt, int l, int r) {
if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt].tag;
int mid = tr[rt].l + tr[rt].r >> 1, ans = 0;
if (l <= mid) umax(ans, ask(rt << 1, l, r));
if (r > mid) umax(ans, ask(rt << 1 | 1, l, r));
return ans;
}
} bit;
int n, m, _, k;
int h[M], ne[N], pre[N];
int main() {
IOS; cin >> n >> k;
rep(i, 1, n) ne[i] = n + 1;
rep(i, 1, n) cin >> m, ne[pre[i] = h[m]] = i, h[m] = i;
bit.build(1, 1, n, pre);
rep(i, 1, k) {
int op, l, r; cin >> op >> l;
if (op == 1) {
bit.change(1, l, 0);
if (pre[l]) ne[pre[l]] = ne[l];
if (ne[l] != n + 1) bit.change(1, ne[l], pre[ne[l]] = pre[l]);
}
else {
cin >> r;
cout << (l <= bit.ask(1, l, r)) << '\n';
}
}
return 0;
}
F 匹配串
答案明显要么无限要么为0
正反个匹配一次即可, 记录每个串正着和倒着第一次出现'#' 的位置
比如 a#cd#e, a#ef#e, 只要这两个串的正着和倒着到 '#'之前的字串匹配, 那就匹配, 中间的可以用#代替
a#cd#e = aefcde, a#ed#e = aedcde, 当然这只是一种情况, 答案是无限
int main() {
IOS; cin >> n;
rep (i, 1, n) cin >> s[i].s, umax(mx, s[i].s.size());
rep (i, 1, n) {
rep (j, 0, s[i].s.size() - 1) if (s[i].s[j] == '#') { s[i].p1 = j; break; }
per (j, s[i].s.size() - 1, 0) if (s[i].s[j] == '#') { s[i].p2 = s[i].s.size() - 1 - j; break; }
}
sort(s + 1, s + n + 1, [](node &a, node &b) { return a.p1 < b.p1; });
int nw = 1; bool f = 0;
rep (i, 0, mx) {
while (s[nw].s[i] == '#' && nw < n) ++nw;
if (nw == n) break;
char tmp = s[nw].s[i];
rep (j, nw + 1, n) if (s[j].s[i] != tmp) { f = 1; break; }
}
sort(s + 1, s + n + 1, [](node &a, node &b) { return a.p2 < b.p2; });
nw = 1;
rep (i, 1, mx - 1) {
while (s[nw].s[s[nw].s.size() - i] == '#' && nw < n) ++nw;
if (nw == n) break;
char tmp = s[nw].s[s[nw].s.size() - i];
rep (j, nw + 1, n) if (s[j].s[s[j].s.size() - i] != tmp) { f = 1; break; }
}
cout << (f ? 0 : -1);
return 0;
}
G 糖果
权值并查集
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void unit(int x, int y) { x = find(x); y = find(y); if (x != y) f[y] = x, umax(a[x], a[y]), sz[x] += sz[y]; }
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) cin >> a[i], f[i] = i, sz[i] = 1;
rep (i, 1, m) {
int u, v; cin >> u >> v;
unit(u, v);
}
rep (i, 1, n) if (f[i] == i) ans += sz[i] * a[i];
cout << ans;
return 0;
}
H 数字串
int main() {
IOS; cin >> s; string t = ""; bool f = 0;
for (int i = 0; s[i]; ++i)
if (s[i] > 'j' && s[i] != 't') {
rep (j, 0, i - 1) t += s[j];
t += (s[i] - 'a' + 1) / 10 + 'a' - 1;
t += (s[i] - 'a' + 1) % 10 + 'a' - 1;
for (int j = i + 1; s[j]; ++j) t += s[j];
f = 1; break;
} else if (s[i + 1] && max(s[i], s[i + 1]) < 'j' && (s[i] - 'a' + 1) * 10 + (s[i + 1] - 'a' + 1) <= 26) {
rep (j, 0, i - 1) t += s[i];
t += (s[i] - 'a' + 1) * 10 + (s[i + 1] - 'a' + 1) + 'a' - 1;
for (int j = i + 2; s[j]; ++j) t += s[j];
f = 1; break;
}
if (f) cout << t;
else cout << -1;
return 0;
}
I 序列的美观度
贪心, 在 (a[i] == a[j]) i~j 之间出现相同的数直接舍弃当前 i 即可
int main() {
IOS; cin >> n; unordered_set<int> st;
rep (i, 1, n) {
cin >> a[i];
if (st.count(a[i])) ++m, unordered_set<int>().swap(st);
st.insert(a[i]);
}
cout << m;
return 0;
}
J 加法和乘法
数据才 1e6, 直接模拟游戏比赛即可
int main() {
IOS; cin>>n; int ji = 0, ou = 0;
rep (i ,1, n) cin >> m, ji += m % 2; ou = n - ji;
while(ou + ji > 1) {
if (ou >= 2) --ou;
else if (ou >= 1 && ji >= 1) --ou;
else if (ji >= 2) --ji;
if (ji >= 2) ji -= 2, ++ou;
else if (ji >= 1 && ou >= 1) --ji;
else if(ou >= 2) --ou;
}
if (ou) cout << "NiuMei";
else cout << "NiuNiu";
return 0;
}