比赛链接
A. lz的吃饭问题
题目大意
给出四个整数 a , b , c , d a, \ b, \ c,\ d a, b, c, d,若 a ⋅ b < c ⋅ d a \cdot b < c \cdot d a⋅b<c⋅d 则输出 l z lz lz,否则输出 g z y gzy gzy。
Solution
按照题意模拟即可。
C++ Code
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int a, b;
std::cin >> a >> b;
int c, d;
std::cin >> c >> d;
if (a * b < c * d) {
std::cout << "lz\n";
} else {
std::cout << "gzy\n";
}
return 0;
}
B. lz的数字问题
题目大意
给出两个浮点数 a , b a, \ b a, b,判断它们是否相等。
- 相等的意思是 a a a 和 b b b 的整数部分相同,且小数点后六位相同。
数据范围
- 1 ⩽ ∣ a ∣ , ∣ b ∣ ⩽ 2 × 1 0 5 1 \leqslant |a|, \ |b| \leqslant 2 \times 10^5 1⩽∣a∣, ∣b∣⩽2×105
Solution
用字符串读入浮点数。以 a a a 为例,若 a a a 小数部分超过 6 6 6 位,删掉后面的数位,否则加到 6 6 6 位。
C++ Code
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::string a, b;
std::cin >> a >> b;
auto work = [&](auto &s) {
int p = s.find('.');
if (p != -1) {
while (s.size() - p - 1 < 6) {
s += '0';
}
while (s.size() - p - 1 > 6) {
s.pop_back();
}
} else {
s += '.' + std::string(6, '0');
}
return s;
};
std::cout << (work(a) == work(b) ? "YES\n": "NO\n");
return 0;
}
C. lz的蛋挞问题
题目大意
给定一个 2 × n 2 \times n 2×n 的 01 01 01 矩阵,其中挨着的若干个 0 0 0 会形成连通块,设当前有 c n t cnt cnt 个连通块。现在要求你选一个位置 ( i , j ) (i, \ j) (i, j)( 1 ⩽ i ⩽ 2 , 1 ⩽ j ⩽ n 1 \leqslant i \leqslant 2, \ 1 \leqslant j \leqslant n 1⩽i⩽2, 1⩽j⩽n),满足 g [ i ] [ j ] = 0 g[i][j] = 0 g[i][j]=0,将其变为 g [ i ] [ j ] = 1 g[i][j] = 1 g[i][j]=1 后,使得连通块数量变为 c n t − 1 cnt -1 cnt−1。问这样的位置 ( i , j ) (i, \ j) (i, j) 有多少个。
Solution
我们把要从 0 0 0 变 1 1 1 的位置成为中心点。
考虑下面三种形状:
- 左上角的 0 0 0 为中心点 0 0 0 1 \begin{matrix} 0 & 0 \\ 0 & 1 \end{matrix} 0001
- 右上角的 0 0 0 为中心点 0 0 1 0 \begin{matrix} 0 & 0 \\ 1 & 0 \end{matrix} 0100
- 第一排中心的 0 0 0 为中心点 0 0 0 1 \begin{matrix} 0 & 0 & 0 \\ & 1 & \end{matrix} 0010
可以发现,这三种情况下,如果把中心点变成 1 1 1,就能阻断原先的连通块。
除此之外,还有一种特殊情况就是单个 0 0 0 成为连通块,即四面都是 1 1 1 的情况,也能减少连通块。
C++ Code
#include <bits/stdc++.h>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::array<std::vector<int>, 2> g{};
for (int i = 0; i < 2; i++) {
g[i].assign(n, 0);
for (int j = 0; j < n; j++) {
char c;
std::cin >> c;
if (c == 'x') {
g[i][j] = 1;
}
}
}
if (n == 1) {
std::cout << (g[0][0] or g[1][0]) << "\n";
return 0;
}
auto calc = [&](int r) {
int res = 0;
for (int i = 0; i < n; i++) {
if (g[r][i]) {
continue;
}
bool ok = false;
if (i > 0) {
if (!g[r][i - 1] and !g[r ^ 1][i] and g[r ^ 1][i - 1]) {
ok = true;
}
}
if (i + 1 < n) {
if (!g[r][i + 1] and !g[r ^ 1][i] and g[r ^ 1][i + 1]) {
ok = true;
}
}
if (i > 0 and i + 1 < n) {
if (!g[r][i - 1] and !g[r][i + 1] and g[r ^ 1][i]) {
ok = true;
}
}
if ((i == 0 or g[r][i - 1]) and (i == n - 1 or g[r][i + 1]) and g[r ^ 1][i]) {
ok = true;
}
res += ok;
}
return res;
};
int ans = calc(0) + calc(1);
std::cout << ans << "\n";
return 0;
}
D. lz的染色问题
题目大意
给定一个长度为
n
n
n 的数组
c
c
c 和
m
m
m 个下标对
(
p
i
,
p
j
)
(p_i, \ p_j)
(pi, pj),满足
1
⩽
p
i
,
p
j
⩽
n
1 \leqslant p_i, \ p_j \leqslant n
1⩽pi, pj⩽n。
一次操作可以改变一个指定的
c
i
(
1
⩽
i
⩽
n
)
c_i(1 \leqslant i \leqslant n)
ci(1⩽i⩽n),求至少要多少次操作,使得这
m
m
m 对
(
p
i
,
p
j
)
(p_i, \ p_j)
(pi, pj) 都满足
c
p
i
=
c
p
j
c_{p_i} = c_{p_j}
cpi=cpj。
Solution
显然是并查集,直接把 m m m 对下标合并了,然后记录每个连通块里每种颜色的出现次数。设第 i i i 个连通块颜色的出现次数的集合是 C i C_i Ci,共有 k k k 个连通块,则答案为 ∑ i = 1 k ( s u m ( C i ) − max ( C i ) ) \sum\limits_{i = 1}^{k} (sum(C_i) - \max(C_i)) i=1∑k(sum(Ci)−max(Ci))
C++ Code
#include <bits/stdc++.h>
struct DSU {
std::vector<int> f, sz;
DSU() {}
DSU(int n) {
init(n);
}
void init(int n) {
f.resize(n);
std::iota(f.begin(), f.end(), 0);
sz.assign(n, 1);
}
int find(int x) {
while (x != f[x]) {
x = f[x] = f[f[x]];
}
return x;
}
int size(int x) {
return sz[find(x)];
}
bool merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return false;
}
sz[x] += sz[y];
f[y] = x;
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> c(n);
for (int i = 0; i < n; i++) {
std::cin >> c[i];
}
DSU dsu(n);
for (int i = 0; i < m; i++) {
int u, v;
std::cin >> u >> v;
u--, v--;
dsu.merge(u, v);
}
std::vector<std::map<int, int>> cnt(n);
for (int i = 0; i < n; i++) {
cnt[dsu.find(i)][c[i]]++;
}
int ans = 0;
for (int i = 0; i < n; i++) {
if (dsu.find(i) == i) {
int max = 0;
int sum = 0;
for (const auto &[c, v]: cnt[i]) {
max = std::max(max, v);
sum += v;
}
ans += sum - max;
}
}
std::cout << ans << "\n";
return 0;
}
E. lz的括号问题
题目大意
给定一个长度为 2 n 2n 2n 的括号序列 s s s,若其 非法,输出 − 1 -1 −1。
否则,我们对 s s s 按照左括号的出现顺序进行编号,例如 s = ( ( ) ) ( ) s = (())() s=(())() 就会被编号为 122133 122133 122133。
对于每个编号 i ∈ [ 1 , n ] i \in [1, \ n] i∈[1, n],求在删除 i i i 之前,至多 还能删掉多少编号。
- 每次删除只能删除一个连续两个相同编号,且删完后字符串向中心靠拢重排,
- 例如对于上述 122133 122133 122133,可以删除 22 22 22,删后变为 1133 1133 1133;可以删除 33 33 33,删后变为 1221 1221 1221;但不能删除 11 11 11,因为它不连续,也不能删除 12 12 12,因为它不相同。
下面举例说明: s = ( ( ( ) ) ( ) ( ) ) ( ( ) ) s = ((())()())(()) s=((())()())(()),编号为 12332445516776 12332445516776 12332445516776。
对于编号 2 2 2,我 至多 可以先删除 5 5 5 个其他编号,再来删它。一种删除办法是:
- 删除 33 33 33,变为 122445516776 122445516776 122445516776,
- 删除 44 44 44,变为 1225516776 1225516776 1225516776,
- 删除 55 55 55,变为 12216776 12216776 12216776,
- 删除 77 77 77,变为 122166 122166 122166,
- 删除 66 66 66,变为 1221 1221 1221。
Sample
样例输入
5
((()))(())
样例输出
4 3 2 4 3
Solution
首先我们认为对于每个编号
i
d
x
idx
idx,除了
i
d
x
idx
idx 其他编号全都能在它之前删,也就是答案初始值为
n
−
1
n - 1
n−1。然后维护一个括号序列的前缀,见到 (
就进栈,见到 )
就出栈(如果栈非空)。
- 当我们遇到
(
时,设它的编号为 i d x idx idx,此时栈内全都是之前出现过的无法匹配的(
,同时还要被 i d x idx idx 这个编号压着,所以 a n s [ i d x ] = ( n − 1 ) − s t a c k . s i z e ( ) ans[idx] = (n - 1) - stack.size() ans[idx]=(n−1)−stack.size(), - 当我们遇到
)
时,若栈非空且栈顶是(
,直接出栈,否则返回 − 1 -1 −1。
C++ Code
#include <bits/stdc++.h>
template<class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &a) {
os << a[0];
for (int i = 1; i < a.size(); i++) {
os << " " << a[i];
}
return os;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::string s;
std::cin >> s;
int idx = 0;
std::string stk;
std::vector<int> ans(n, n - 1);
for (auto c: s) {
if (c == '(') {
ans[idx++] -= stk.size();
stk += c;
} else if (!stk.empty() and stk.back() == '(') {
stk.pop_back();
} else {
std::cout << "-1\n";
return 0;
}
}
std::cout << ans << "\n";
return 0;
}
F. lz的序列问题
题目大意
给定一个长度为 n n n 的序列 a a a。
定义 s ( l , r ) = a l + ( a l ⋅ a l + 1 ) + ( a l ⋅ a l + 1 ⋅ a l + 2 ) + ⋯ + ( a l ⋅ a l + 1 ⋯ a r ) s(l, \ r) = a_l + (a_l \cdot a_{l + 1}) + (a_l \cdot a_{l + 1} \cdot a_{l + 2}) + \cdots + (a_l \cdot a_{l + 1} \cdots a_r) s(l, r)=al+(al⋅al+1)+(al⋅al+1⋅al+2)+⋯+(al⋅al+1⋯ar)。
现在有 q q q 次询问,每次询问如下:
1 l r x
:把 a l a_l al 到 a r a_r ar 都修改为 x x x,2 l r
:输出 s ( l , r ) s(l, \ r) s(l, r),答案对 1000000007 1000000007 1000000007 取模。
Solution
线段树板子题,因为 s ( l , r ) s(l, \ r) s(l, r) 可以分治求解。
对每个线段树区间 [ l , r ] [l, \ r] [l, r] 维护一个 s ( l , r ) s(l, \ r) s(l, r) 和 m ( l , r ) m(l, \ r) m(l, r),其中 m ( l , r ) = ∏ i = l r a i m(l, \ r) = \prod\limits_{i = l}^{r}{a_i} m(l, r)=i=l∏rai。
设 [ l , r ] [l, \ r] [l, r] 被分为 [ l , b ] [l, \ b] [l, b] 和 [ b + 1 , r ] [b + 1, \ r] [b+1, r],那么我们有
m ( l , r ) = m ( l , b ) ⋅ m ( b + 1 , r ) s ( l , r ) = s ( l , b ) + s ( b + 1 , r ) ⋅ m ( b + 1 , r ) \begin{align*} m(l, \ r) &= m(l, \ b) \cdot m(b + 1, \ r) \\ s(l, \ r) &= s(l, \ b) + s(b + 1, \ r) \cdot m(b + 1, \ r) \end{align*} m(l, r)s(l, r)=m(l, b)⋅m(b+1, r)=s(l, b)+s(b+1, r)⋅m(b+1, r)
对于修改操作,我们记录一个 t a g tag tag,表示要区间推平的数值,则修改操作如下:
- m ( l , r ) = t a g r − l + 1 m(l, \ r) = tag^{r - l + 1} m(l, r)=tagr−l+1,
- s ( l , r ) = { r − l + 1 , t a g = 1 t a g ⋅ m ( l , r ) − 1 t a g − 1 , t a g ≠ 1 s(l, \ r) = \begin{cases} r - l + 1 ,& tag = 1 \\ tag \cdot \frac{m(l, \ r) - 1}{tag - 1}, & tag \neq 1 \end{cases} s(l, r)={r−l+1,tag⋅tag−1m(l, r)−1,tag=1tag=1
C++ Code
#include <bits/stdc++.h>
using i64 = int64_t;
template<class T>
constexpr T power(T a, i64 b) {
T res = 1;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
template<int P>
struct MInt {
int x;
constexpr MInt() : x{} {}
constexpr MInt(i64 x) : x{norm(x % getMod())} {}
static int Mod;
constexpr static int getMod() {
if (P > 0) {
return P;
} else {
return Mod;
}
}
constexpr static void setMod(int Mod_) {
Mod = Mod_;
}
constexpr int norm(int x) const {
if (x < 0) {
x += getMod();
}
if (x >= getMod()) {
x -= getMod();
}
return x;
}
constexpr int val() const {
return x;
}
explicit constexpr operator int() const {
return x;
}
constexpr MInt operator-() const {
MInt res;
res.x = norm(getMod() - x);
return res;
}
constexpr MInt inv() const {
assert(x != 0);
return power(*this, getMod() - 2);
}
constexpr MInt &operator*=(MInt rhs) & {
x = 1LL * x * rhs.x % getMod();
return *this;
}
constexpr MInt &operator+=(MInt rhs) & {
x = norm(x + rhs.x);
return *this;
}
constexpr MInt &operator-=(MInt rhs) & {
x = norm(x - rhs.x);
return *this;
}
constexpr MInt &operator/=(MInt rhs) & {
return *this *= rhs.inv();
}
friend constexpr MInt operator*(MInt lhs, MInt rhs) {
MInt res = lhs;
res *= rhs;
return res;
}
friend constexpr MInt operator+(MInt lhs, MInt rhs) {
MInt res = lhs;
res += rhs;
return res;
}
friend constexpr MInt operator-(MInt lhs, MInt rhs) {
MInt res = lhs;
res -= rhs;
return res;
}
friend constexpr MInt operator/(MInt lhs, MInt rhs) {
MInt res = lhs;
res /= rhs;
return res;
}
friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
i64 v;
is >> v;
a = MInt(v);
return is;
}
friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
return os << a.val();
}
friend constexpr bool operator==(MInt lhs, MInt rhs) {
return lhs.val() == rhs.val();
}
friend constexpr bool operator!=(MInt lhs, MInt rhs) {
return lhs.val() != rhs.val();
}
};
template<>
int MInt<0>::Mod = 998244353;
template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();
constexpr int P = 1000000007;
using Z = MInt<P>;
template<class Info, class Tag>
struct LSGT {
#define l(p) (p << 1)
#define r(p) (p << 1 | 1)
int n;
std::vector<Info> info;
std::vector<Tag> tag;
LSGT() {}
LSGT(int _n, Info _v = Info()) {
init(_n, _v);
}
template<class T>
LSGT(std::vector<T> _init) {
init(_init);
}
void init(int _n, Info _v = Info()) {
init(std::vector(_n, _v));
}
template<class T>
void init(std::vector<T> _init) {
n = _init.size();
info.assign(4 << std::__lg(n), Info());
tag.assign(4 << std::__lg(n), Tag());
auto build = [&](auto self, int p, int l, int r) {
if (r - l == 1) {
info[p] = _init[l];
return;
}
int m = l + r >> 1;
self(self, l(p), l, m);
self(self, r(p), m, r);
pull(p);
};
build(build, 1, 0, n);
}
void pull(int p) {
info[p] = info[l(p)] + info[r(p)];
}
void apply(int p, const Tag &v, int len) {
info[p].apply(v, len);
tag[p].apply(v);
}
void push(int p, int len) {
apply(l(p), tag[p], len / 2);
apply(r(p), tag[p], len - len / 2);
tag[p] = Tag();
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = v;
return;
}
int m = l + r >> 1;
push(p, r - l);
if (x < m) {
modify(l(p), l, m, x, v);
} else {
modify(r(p), m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
Info query(int p, int l, int r, int x, int y) {
if (l >= y or r <= x) {
return Info();
}
if (l >= x and r <= y) {
return info[p];
}
int m = l + r >> 1;
push(p, r - l);
return query(l(p), l, m, x, y) + query(r(p), m, r, x, y);
}
Info query(int l, int r) {
return query(1, 0, n, l, r);
}
void Apply(int p, int l, int r, int x, int y, const Tag &v) {
if (l >= y or r <= x) {
return;
}
if (l >= x and r <= y) {
apply(p, v, r - l);
return;
}
int m = l + r >> 1;
push(p, r - l);
Apply(l(p), l, m, x, y, v);
Apply(r(p), m, r, x, y, v);
pull(p);
}
void Apply(int l, int r, const Tag &v) {
return Apply(1, 0, n, l, r, v);
}
template<class F>
int findFirst(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y or r <= x) {
return -1;
}
if (l >= x and r <= y and !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = l + r >> 1;
int res = findFirst(l(p), l, m, x, y, pred);
if (res == -1) {
res = findFirst(r(p), m, r, x, y, pred);
}
return res;
}
template<class F>
int findFirst(int l, int r, F &&pred) {
return findFirst(1, 0, n, l, r, pred);
}
template<class F>
int findLast(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y or r <= x) {
return -1;
}
if (l >= x and r <= y and !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = l + r >> 1;
int res = findLast(r(p), m, r, x, y, pred);
if (res == -1) {
res = findLast(l(p), l, m, x, y, pred);
}
return res;
}
template<class F>
int findLast(int l, int r, F &&pred) {
return findLast(1, 0, n, l, r, pred);
}
#undef l(p)
#undef r(p)
};
struct Tag {
int tag = 0;
void apply(const Tag &t) {
if (t.tag != 0) {
tag = t.tag;
}
}
};
struct Info {
Z sum = 0;
Z mul = 1;
void apply(const Tag &t, int len) {
if (t.tag != 0) {
mul = power(Z(t.tag), len);
if (t.tag == 1) {
sum = len;
} else {
sum = t.tag * (mul - 1) / (t.tag - 1);
}
}
}
};
Info operator+(const Info &a, const Info &b) {
return {a.sum + a.mul * b.sum, a.mul * b.mul};
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
int n, q;
std::cin >> n >> q;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
}
LSGT<Info, Tag> sgt(n);
for (int i = 0; i < n; i++) {
sgt.modify(i, {a[i], a[i]});
}
while (q--) {
int o, l, r;
std::cin >> o >> l >> r;
l--;
if (o == 1) {
int x;
std::cin >> x;
sgt.Apply(l, r, {x});
} else {
std::cout << sgt.query(l, r).sum << "\n";
}
}
return 0;
}