VP Educational Codeforces Round 23


A. Treasure Hunt

题意:你要从(x1,y1)走到(x2,y2),每次横坐标必须移动x个单位,纵坐标必须移动y个单位。求能不能到达。

先看两个坐标的的距离能不能整除x,y,然后看走的步数是不是奇偶性相同,如果相同则一个坐标可以通过反复横跳来等另一个坐标到位。否则不行。

点击查看代码
void solve() {
    int x1, y1, x2, y2, x, y;
    std::cin >> x1 >> y1 >> x2 >> y2 >> x >> y;
    if ((x1 - x2) % x == 0 && (y1 - y2) % y == 0 && std::abs(x1 - x2) / x % 2 == std::abs(y1 - y2) / y % 2) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

B. Makes And The Product

题意:求数组选三个数有多少组是乘积最小的。

先从小到大排序,如果最小的出现超过三次,则答案为最小数里选两个的方案,如果最小的出现两次,答案为第二小的出现的次数,否则看第二小的数出现几次,类似的讨论。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::sort(a.begin(), a.end());
    if (a[2] == a[0]) {
    	i64 cnt = std::count(a.begin(), a.end(), a[0]);
    	std::cout << cnt * (cnt - 1) * (cnt - 2) / 6 << "\n";
    } else if (a[1] == a[0]) {
    	std::cout << std::count(a.begin(), a.end(), a[2]) << "\n";
    } else if (a[2] == a[1]) {
    	i64 cnt = std::count(a.begin(), a.end(), a[2]);
    	std::cout << cnt * (cnt - 1) / 2 << "\n";
    } else {
    	std::cout << std::count(a.begin(), a.end(), a[2]) << "\n";
    }
}

C. Really Big Numbers

题意:求[1,n]里满足iDis的数量,其中Dii的数位和。

一个数加一,其数位和最多加一,且最多加10次数位和就会减少若干个9。所以只有iDis,则[i,n]的数都满足条件。从s开始枚举即可,根据上述讨论,很快就能找到满足条件的最小数。

点击查看代码
void solve() {
    i64 n, s;
    std::cin >> n >> s;
    if (s > n) {
    	std::cout << 0 << "\n";
    	return;
    }

    for (i64 i = s; i <= n; ++ i) {
    	i64 x = i, sum = 0;
    	while (x) {
    		sum += x % 10;
    		x /= 10;
    	}

    	if (i - sum >= s) {
    		std::cout << n - i + 1 << "\n";
    		return;
    	}
    }

    std::cout << 0 << "\n";
}

D. Imbalanced Array

题意:求所有子数组的最大值减最小值的和。

求出每个数作为最大值的左右边界lmaxi,rmaxi和作为最小值的左右边界lmini,rmini,则如果我们选择i这个数,它作为最大值会贡献(ilmaxi+1)×(rmaxii+1),同理作为最小值会贡献(ilmin+1)×(rminii+1)
可以用单调栈求lmax,rmax,lmin,rmin

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n + 2);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> a[i];
    }

    std::stack<std::pair<int, int>> stk;
    a[0] = a[n + 1] = 1e9;
    stk.push({a[0], 0});
    std::vector<int> lmax(n + 2), rmax(n + 2);
    for (int i = 1; i <= n + 1; ++ i) {
    	while (a[i] > stk.top().first) {
    		rmax[stk.top().second] = i - 1;
    		stk.pop();
    	}

    	lmax[i] = stk.top().second + 1;
    	stk.push({a[i], i});
    }

    while (stk.size()) {
    	stk.pop();
    }

    a[0] = a[n + 1] = -1e9;
    stk.push({a[0], 0});
    std::vector<int> lmin(n + 2), rmin(n + 2);
    for (int i = 1; i <= n + 1; ++ i) {
    	while (a[i] < stk.top().first) {
    		rmin[stk.top().second] = i - 1;
    		stk.pop();
    	}

    	lmin[i] = stk.top().second + 1;
    	stk.push({a[i], i});
    }

    i64 ans = 0;
    for (int i = 1; i <= n; ++ i) {
    	ans += (i64)a[i] * ((i64)(i - lmax[i] + 1) * (rmax[i] - i + 1) - (i64)(i - lmin[i] + 1) * (rmin[i] - i + 1));
    }

    std::cout << ans << "\n";
}

E. Choosing The Commander

题意:每次插入一个x或者删除一个x,或者求有多少x满足xy<z

用字典树维护每一位有多少数经过,那么对于一个查询,我们贴着z走,设zi,yiz,x的第i位的值。如果zi=1,则答案加上tr[p][x]

点击查看代码
const int N = 1e6 + 5;

int trie[N * 30][2];
int node_cnt[N * 30];
struct TrieWith01 {
	int idx;
	int creat() {
		memset(trie[idx], 0, sizeof trie[idx]);
		node_cnt[idx] = 0;
		return idx ++ ;
	}

	TrieWith01() {
		idx = 0;
		creat();
	}

	void insert(int x) {
		int p = 0;
		for (int i = 29; i >= 0; -- i) {
			int s = x >> i & 1;
			if (!trie[p][s]) {
				trie[p][s] = creat();
			}

			p = trie[p][s];
			++ node_cnt[p];
		}
	}

	void insert(int x, int v) {
		int p = 0;
		for (int i = 29; i >= 0; -- i) {
			int s = x >> i & 1;
			if (!trie[p][s]) {
				trie[p][s] = creat();
			}

			p = trie[p][s];
			node_cnt[p] += v;
		}
	}

	int xor_max(int x) {
		int p = 0;
		int res = 0;
		for (int i = 29; i >= 0; -- i) {
			int s = x >> i & 1;
			if (trie[p][!s]) {
				res += 1 << i;
				p = trie[p][!s];
			} else {
				p = trie[p][s];
			}
		}

		return res;
	}

	int query_geq(int x, int k, bool eq = true) {
		int p = 0;
		int res = 0;
		for (int i = 29; i >= 0; -- i) {
			int a = x >> i & 1, b = k >> i & 1;
			if (b == 1) {
				p = trie[p][a ^ 1];
			} else {
				res += node_cnt[trie[p][a ^ 1]];
				p = trie[p][a];
			}

			if (p == 0) {
				break;
			}
		}

		if (eq) {
			res += node_cnt[p];
		}

		return res;
	}

	int query_leq(int x, int k, bool eq = true) {
		int p = 0;
		int res = 0;
		for (int i = 29; i >= 0; -- i) {
			int a = x >> i & 1, b = k >> i & 1;
			if (b == 1) {
				res += node_cnt[trie[p][a]];
				p = trie[p][a ^ 1];
			} else {
				p = trie[p][a];
			}

			if (p == 0) {
				break;
			}
		}

		if (eq) {
			res += node_cnt[p];
		}

		return res;
	}
};

void solve() {
    int q;
    std::cin >> q;
    TrieWith01 tr;
    while (q -- ) {
    	int op, x, y;
    	std::cin >> op >> x;
    	if (op == 1) {
    		tr.insert(x, 1);
    	} else if (op == 2) {
    		tr.insert(x, -1);
    	} else {
    		std::cin >> y;
    		std::cout << tr.query_leq(x, y, false) << "\n";
    	}
    }
}

F. MEX Queries

题意:q次操作,每次把[l,r]都加进来,或者把[l,r]都删掉,或者把[l,r]里有的数删掉,没有的数删除。每次都要求mex

先把所有数离散化,那么我们可以用线段树维护区间值,懒标记维护set,rev,意味区间赋值和区间翻转。每次优先赋值然后翻转就行。求mex就是线段树二分求第一个区间和不等于区间长度的位置。
注意要把每个r+11也加进来,这样如果[1,r]都有我们就可以得到r+1mex

点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)

template <class Info, class Tag>
struct Node {
	int l, r;
	Info info;
	Tag tag;
};

template <class Info, class Tag>
struct SegmentTreeWithLazy {
	std::vector<Node<Info, Tag> > tr;
	SegmentTreeWithLazy(int _n) {
		init(_n);
	}

	SegmentTreeWithLazy(std::vector<Info> & a) {
		int _n = (int)a.size() - 1;
		init(_n, a);
	}

	void init(int _n) {
		tr.assign(_n << 2, {});
		build(1, _n);
	}

	void init(int _n, std::vector<Info> & a) {
		tr.assign(_n << 2, {});
		build(1, _n, a);
	}

	void pushup(int u) {
		tr[u].info = tr[ls].info + tr[rs].info;
	}

	void pushdown(Node<Info, Tag> & u, Tag tag) {
		u.info = u.info + tag;
		u.tag = u.tag + tag;
	}

	void pushdown(int u) {
		if (tr[u].tag.exist()) {
			pushdown(tr[ls], tr[u].tag);
			pushdown(tr[rs], tr[u].tag);
			tr[u].tag.clear();
		}
	}

	void build(int l, int r, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, ls); build(mid + 1, r, rs);
	}

	void build(int l, int r, std::vector<Info> & a, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			tr[u].info = a[l];
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, a, ls); build(mid + 1, r, a, rs);
		pushup(u);
	}

	void modify(int l, int r, Tag tag, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			pushdown(tr[u], tag);
			return;
		}

		pushdown(u);
		int mid = umid;
		if (l <= mid) {
			modify(l, r, tag, ls);
		}

		if (r > mid) {
			modify(l, r, tag, rs);
		}

		pushup(u);
	}

	Info query(int l, int r, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			return tr[u].info;
		}

		pushdown(u);

		int mid = umid;
		if (r <= mid) {
			return query(l, r, ls);
		}  else if (l > mid) {
			return query(l, r, rs);
		}

		return query(l, r, ls) + query(l, r, rs);
	}

	int query_first_not_appear(int u = 1) {
		if (tr[u].l == tr[u].r) {
			return tr[u].l;
		}

		pushdown(u);
		int mid = umid;
		if (tr[ls].info.sum != tr[ls].info.len) {
			return query_first_not_appear(ls);
		} else {
			return query_first_not_appear(rs);
		}
	}
};

struct Info {
	int sum, len;
};

struct Tag {
	int set, rev;
	bool exist() {	
		return set != -1 || rev != 0;
	}

	void clear() {
		set = -1;
		rev = 0;
	}
};

Info operator + (const Info & a, const Info & b) {
	Info res = a;
	res.sum += b.sum;
	res.len += b.len;
	return res;
}

Info operator + (const Info & a, const Tag & b) {
	Info res = a;
	if (b.set != -1) {
		res.sum = b.set * res.len;
	}

	if (b.rev) {
		res.sum = res.len - res.sum;
	}

	return res;
}

Tag operator + (const Tag & a, const Tag & b) {
	Tag res = a;
	if (b.set != -1) {
		res.set = b.set;
		res.rev = 0;
	}

	res.rev ^= b.rev;
	return res;
}


void solve() {
    int n;
    std::cin >> n;
    std::vector<std::array<i64, 3>> op(n);
    std::vector<i64> b;
    for (int i = 0; i < n; ++ i) {
    	i64 t, l, r;
    	std::cin >> t >> l >> r;
    	op[i] = {t, l, r};
    	b.push_back(l);
    	b.push_back(r);
    	b.push_back(r + 1);
    }

    b.push_back(1);
    std::sort(b.begin(), b.end());
    b.erase(std::unique(b.begin(), b.end()), b.end());
    int m = b.size();
    auto get = [&](i64 x) -> int {
    	return std::lower_bound(b.begin(), b.end(), x) - b.begin() + 1;
    };

    std::vector<Info> info(m + 1);
    for (int i = 1; i <= m; ++ i) {
    	info[i] = {0, 1};
    }

    SegmentTreeWithLazy<Info, Tag> tr(info);
    for (auto & [t, L, R] : op) {
    	int l = get(L), r = get(R);
    	if (t == 1) {
    		tr.modify(l, r, Tag{1, 0});
    	} else if (t == 2) {
    		tr.modify(l, r, Tag{0, 0});
    	} else {
    		tr.modify(l, r, Tag{-1, 1});
    	}

    	std::cout << b[tr.query_first_not_appear() - 1] << "\n";
    }
}
posted @   maburb  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示