7/12 训练笔记
闲话
打 OI Bingo 然后大力卡时卡空间,贺了最优解之后成功 Bingo.
rep (i, 0, (int)v.size() - 1) v.push_back(1);
在 vector v 本来就有内容的情况下会持续循环。
rep (i, 1, n) rep (i, 1, n) cin >> a[i];
似乎会出问题。
P4137 Rmq Problem / mex
回滚莫队题,莫队笔记。
考虑 mex
在删除时是好维护的:维护一个 cnt
数组,删空了就和 mex
比一下哪个小,然后更新。
但是添加不好做,所以使用回滚莫队。
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; i++)
using namespace std;
int B;
int a[200010], b[200010], bel[200010], cnt[200010], cnt1[200010], ans[200010], st[1010], res[1010], n, m, mex;
int id(int x) {
return bel[x];
}
struct query {
int l, r, id1;
query(int l = 0, int r = 0, int id1 = 0):l(l), r(r), id1(id1) {}
bool operator<(query o) {
return (id(l) != id(o.l)) ? id(l) < id(o.l) : r > o.r;
}
query operator=(query o) {
l = o.l;
r = o.r;
id1 = o.id1;
return *this;
}
}q[200010];
void del(int x) {
cnt[x]--;
if (!cnt[x]) mex = min(mex, x);
}
int bruteForce(int l, int r) {
int mex = 0;
int mmin = 0x3f3f3f3f, mmax = 0;
rep (i, l, r) {
mmin = min(mmin, a[i]);
mmax = max(mmax, a[i]);
}
rep (i, 0, mmax + 1) {
cnt1[i] = 0;
}
rep (i, l, r) {
cnt1[a[i]]++;
}
rep (i, 0, mmax + 1) {
if (cnt1[i] == 0) {
mex = i;
break;
}
}
return mex;
}
int main() {
cin >> n >> m;
B = sqrt(n);
rep (i, 1, n) {
cin >> a[i];
bel[i] = (i - 1) / B + 1;
if (!st[bel[i]]) st[bel[i]] = i;
// cout << bel[i] << " ";
cnt[a[i]]++;
}
// cout << "\n";
rep (i, 1, m) {
cin >> q[i].l >> q[i].r;
q[i].id1 = i;
}
sort(q + 1, q + m + 1);
// rep (i, 1, m) {
// cout << q[i].l << " " << q[i].r << "\n";
// }
mex = bruteForce(1, n);
rep (i, 1, (n - 1) / B + 1) {
res[i] = bruteForce(st[i], n);
// cout << st[i] << " " << n << " " << bruteForce(st[i], n) << "\n";
}
// rep (i, 46, 83) {
// cout << a[i] << " ";
// }
// cout << "\n";
// rep (i, 64, 97) {
// cout << a[i] << " ";
// }
// cout << "\n";
int l = 1, r = n;
rep (i, 1, m) {
if (id(l) != id(q[i].l)) {
l = st[id(q[i].l)];
mex = res[id(l)];
r = n;
rep (i, 1, n) {
cnt[a[i]] = 0;
}
rep (i, l, n) {
cnt[a[i]]++;
}
}
// cout << i << " " << l << " " << mex << "\n";
if (id(q[i].r) != id(l)) {
// if (q[i].l == 66) {
// cout << l << "\n";
// rep (i, 1, 10) {
// cout << cnt[i] << " ";
// }
// cout << "\n";
// cout << mex << "\n";
// }
while (r > q[i].r) del(a[r--]);
int t = mex;
// if (q[i].l == 51) cout << t << " " << l << " " << r << "\n";
// if (q[i].l == 46 && q[i].r == 80) {
// cout << mex << " " << l << " " << r << "\n";
// rep (i, 0, 9) {
// cout << cnt[i] << " ";
// }
// }
int tl = l;
while (l < q[i].l) del(a[l++]);
ans[q[i].id1] = mex;
if (q[i].l == 65) {
// cout << "Here1\n";
// cout << i << " " << mex << "\n";
}
// if (q[i].l == 66) {
// cout << "Here\n";
// cout << i << " " << mex << "\n";
// }
mex = t;
l = tl;
// rep (i, 1, n) {
// cnt[a[i]] = 0;
// }
rep (j, tl, q[i].l - 1) {
cnt[a[j]]++;
}
// if (q[i].l == 51 && q[i].r == 83) {
// cout << "here\n";
// cout << tl << " " << q[i].l << "\n";
// rep (j, tl, q[i].l - 1) {
// cout << i << " " << a[i] << "\n";
// }
// }
// if (q[i].l == 51) {
// cout << l << " " << r << "\n";
// rep (i, 0, 9) {
// cout << cnt[i] << " ";
// }
// cout << "\n";
// }
} else {
ans[q[i].id1] = bruteForce(q[i].l, q[i].r);
}
}
rep (i, 1, m) {
cout << ans[i] << "\n";
}
}
P2558 [AHOI2002] 网络传输
进行一个规律的找。
发现序列实际上是这样构成的(省略了底数 \(k\),只写了指数):\(0, 1, 01, 2, 02, 12, 012, \dots\)。
那么可以发现每次就是加一个数然后把之前的东西连到这个数前面。
那么模拟就好了,__int128
可过。
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; i++)
using namespace std;
void write(__int128 a) {
if (a <= 9) {
putchar(a + '0');
} else {
write(a / 10);
putchar(a % 10 + '0');
}
}
__int128 qpow(int x, int y) {
__int128 a = 1;
rep (i, 1, y) {
a *= x;
}
return a;
}
int k, p;
__int128 ans;
vector<vector<int> > v;
void calc() {
for (auto i:v.back()) {
ans += qpow(k, i);
}
write(ans);
}
int main() {
cin >> k >> p;
p--;
if (p == 0) {
cout << 1 << "\n";
} else {
v.push_back({0});
int cnt = 1;
while (p) {
v.push_back({cnt});
p--;
if (!p) {
calc();
return 0;
}
vector<int> v1;
// cout << "[" << p << " " << v.size() << "]\n";
int sz = v.size() - 2;
rep (i, 0, sz) {
v1.clear();
v1 = v[i];
v1.push_back(cnt);
v.push_back(v1);
p--;
if (!p) {
calc();
return 0;
}
}
// cout << p << " ";
// for (auto i:v.back()) {
// cout << i << " ";
// }
// cout << "\n";
cnt++;
}
}
}
P2673 《瞿葩的数字游戏》T1-数字王国的门神
结论为:答案是 \(\frac{10}{89}\) 的第 \(M\) 至第 \(N\) 位小数。
生成函数应该能把这个推出来吧。
#include <stdio.h>
int m, n, a = 1, b = 89;
int main() {
scanf("%d%d", &m, &n);
for (int i = 1; i <= n + 1; i++) {
a %= b;a *= 10;
if (i >= m + 1) {
printf("%d", a / b);
}
}
}