牛客练习赛85
牛客练习赛85
A - 科学家的模型
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
string s[5];
for (int i = 0; i < 5; ++i)
cin >> s[i];
int x = -1, y, ans = 0;
for (int i = 0; i < 5 && x == -1; ++i)
for (int j = 0; j < 5 && x == -1; ++j)
if (s[i][j] == '1') x = i, y = j;
int len = 0;
while (y + len < 5 && s[x][y + len] == '1')
++len;
for (int i = x + 1; i < 5; ++i) {
if (s[i][y + 1] == '1' && i < 4 && s[i + 1][y] == '1') ans = 8;
if (s[i][y] ^ s[i][y + len - 1]) ans = 9;
if (s[i][y] == '0' && s[i][y + len - 1] == '0') break;
}
cout << ans;
return 0;
}
B - 科学家的模型
尺取, 让你找三段,
那就枚举中间的一段, 预处理左边的和右边的即可
预处理用到尺取
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m, ans = 0;
string s;
cin >> n >> m >> s;
vector<int> cnt(26), l(n), r(n);
for (int i = 0, j = 0; i < n; ++i) {
++cnt[s[i] - 'a'];
while (cnt[s[i] - 'a'] > m && j <= i)
--cnt[s[j++] - 'a'];
l[i] = i ? max(l[i - 1], i - j + 1) : i - j + 1;
}
cnt.assign(cnt.size(), 0);
for (int i = n - 1, j = n - 1; ~i; --i) {
++cnt[s[i] - 'a'];
while (cnt[s[i] - 'a'] > m && i >= i)
--cnt[s[j--] - 'a'];
r[i] = i != n - 1 ? max(r[i + 1], j - i + 1) : j - i + 1;
ans = max(ans, (i ? l[i - 1] : 0) + j - i + 1 + (i != n - 1 ? r[j + 1] : 0));
}
cout << ans;
return 0;
}
C - 哲学家的沉思
典型的倍增题, 复杂度\(O(nlogn)\)
先倍增, 预处理
\(mx(i, j)\) 表示区间 \([i, max(i + 2^j, n)]\) 的最大值
在通过\(mx(i, j)\) 预处理st表的\(st(i, 0)\)
\(st(i, j)\) 表示从位置\(i\)开始包含\(2^j\)个区间能到达最远的右端点(左闭右开)
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, q, ans = 0;
cin >> n >> q;
vector<int> a(n);
for (auto &i : a) cin >> i;
vector<vector<int>> mx(n, vector<int>(17));
for (int i = 0; i < n - 1; ++i)
mx[i][0] = max(a[i], a[i + 1]);
mx[n - 1][0] = 2e9;
for (int j = 1; j < 17; ++j)
for (int i = 0; i < n; ++i)
mx[i][j] = max(mx[i][j - 1], mx[min(i + (1 << j - 1), n - 1)][j - 1]);
vector<vector<int>> st(n + 1, vector<int>(17));
for (int i = 0; i < n; ++i) {
int r = i;
for (int j = 16; ~j; --j)
if (mx[r][j] <= a[i])
r += 1 << j;
st[i][0] = r + 1;
}
st[n][0] = n;
for (int j = 1; j < 17; ++j)
for (int i = 0; i <= n; ++i)
st[i][j] = st[st[i][j - 1]][j - 1];
while (q--) {
int l, r, ans = 1;
cin >> l >> r;
--l, --r;
for (int i = 16; i >= 0; --i)
if (st[l][i] <= r)
ans += 1 << i, l = st[l][i];
cout << ans << '\n';
}
return 0;
}
用bitset维护所含的质数
线段树维护区间bitset即可
const int N = 1e5 + 5, M = 9592;
struct BIT {
static const int N = 5e4 + 5;
bitset<M> tr[N << 2];
void push_up(int p) {
tr[p] = tr[p << 1] | tr[p << 1 | 1];
}
void change(int p, int l, int r, int k, bitset<M> &v) {
if (l == k && r == k) {
tr[p] = v;
return;
}
int mid = l + r >> 1;
if (mid >= k) change(p << 1, l, mid, k, v);
else change(p << 1 | 1, mid + 1, r, k, v);
push_up(p);
}
bitset<M> ask(int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return tr[p];
int mid = l + r >> 1;
if (mid >= R) return ask(p << 1, l, mid, L, R);
if (mid < L) return ask(p << 1 | 1, mid + 1, r, L ,R);
return ask(p << 1, l, mid, L, R) | ask(p << 1 | 1, mid + 1, r, L, R);
}
} bit;
int pri[M], tot;
bool v[N];
bitset<M> ve;
void init(int n) {
for (int i = 2; i <= n; ++i) {
if (!v[i]) pri[tot++] = i;
for (int j = 0; j < tot && pri[j] <= n / i; ++j) {
v[pri[j] * i] = 1;
if (i % pri[j] == 0) break;
}
}
}
void setbit(int n) {
ve = 0;
for (int i = 0; pri[i] <= n / pri[i]; ++i)
if (n % pri[i] == 0) {
ve[i] = 1;
while (n % pri[i] == 0) n /= pri[i];
}
if (n - 1)
ve[lower_bound(pri, pri + tot, n) - pri] = 1;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
init(1e5);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
setbit(x);
bit.change(1, 1, n, i, ve);
}
while (m--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 1) {
setbit(y);
bit.change(1, 1, n, x, ve);
}
else
cout << bit.ask(1, 1, n, x, y).count() << '\n';
}
return 0;
}