1. 程式人生 > 其它 >JZOJ 2022.04.05【省選組】聯訓模擬22

JZOJ 2022.04.05【省選組】聯訓模擬22

總結

一不小心就掛了。。。
題還挺好做的,畢竟是 \(day1\)
知識點上倒沒有盲區,思維難度也沒有那麼高
但做題時還是差了一點味道

\(\text{T1 bamboo}\) 修建竹林

題目大意是給出 \(h_i,m\),構造 \(t_i\) 使得 \(t_i\ge h_i,k|t_i,\sum{t_i-h_i} < m\),求最大的 \(k\)
\(m\le 10^{11},n\le 100, h_i\le 10^9\)

式子變一下

\[k\sum{\lceil \frac{h_i}{k} \rceil}< m+\sum{h_i} \]

一個向上取整的數論分塊
對於一個 \(s = \lceil \frac{h_i}{k}\rceil\)

,有最大的 \(j\) 使得 \(\lceil \frac{h_i}{j} \rceil = s\),則 \(js \le n + j - 1\)\(j = \lfloor \frac{h_i-1}{s-1}\rfloor\)
那麼就可以 \(O(n^2\sqrt h)\) 來做了
比賽時沒有注意答案上限
其實當答案可以達到 \(\max h_i\),可以直接算出最大的 \(k\)\(k= \lfloor\frac{m+\sum h_i-1}{n}\rfloor\)
注意是 \(\text{long long}\) 範圍的值。之後就是可以把上限設為 \(\max h_i\)

\(\text{T2 card}\)
選擇卡牌

題目大意是給出 \(n\) 個三元組 \((a_i,b_i,c_i)\),問有多少個三元組 \((x,y,z),1\le x\le A,1\le y\le B,1\le z\le C\) 滿足這個三元組大於所有的 \(n\) 個三元組
定義大於是指對於 \((x,y,z),(a,b,c)\) 有至少兩個位嚴格大於另一個對應的兩個位

發現不好統計,容斥什麼的毫無頭緒,那就先理性分析,暴力嘗試
欽定一個 \(z\),考慮 \(x\)\(1..A\)\(y\) 的範圍,記為 \(f_x\)
\(z\) 從大到小時限制越來越嚴,也就是 \(f_x\) 越來越緊,考慮臨界點的變化即可
發現有區間取最值的操作,吉司機線段樹?
其實觀察 \(f_x\)

,當 \(x\) 減小時 \(f_x\) 也是越來越緊的
於是可以改為區間賦值操作

\(\text{Code}\)

#include <cstdio> 
#include <iostream>
#include <algorithm>
#define RE register
#define IN inline
using namespace std;
typedef long long LL;

const int N = 7e5 + 5;
int n, A, B, C, suf[N], h[N], tot;
LL ans;
struct node{int a, b, c;}p[N];
IN bool cmpA(node x, node y){return x.a > y.a;}
struct edge{int to, nxt;}e[N];
IN void add(int x, int y){e[++tot] = edge{y, h[x]}, h[x] = tot;}

IN void read(int &x)
{
	x = 0; char ch = getchar(); int f = 1;
	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
	x *= f;
}

struct SegTree{
	#define ls (p << 1)
	#define rs (ls | 1)
	#define mid ((l + r) >> 1)
	LL sum[N * 4]; int mn[N * 4], tag[N * 4];
	IN void pushup(int p){sum[p] = sum[ls] + sum[rs], mn[p] = min(mn[ls], mn[rs]);}
	IN void push(int p, int l, int r, int v){tag[p] = v, sum[p] = (LL)v * (r - l + 1), mn[p] = v;}
	IN void pushdown(int p, int l, int r){if (tag[p]) push(ls, l, mid, tag[p]), push(rs, mid + 1, r, tag[p]), tag[p] = 0;}
	void build(int p, int l, int r)
	{
		if (l == r) return sum[p] = mn[p] = suf[l], void();
		build(ls, l, mid), build(rs, mid + 1, r), pushup(p);
	}
	void update(int p, int l, int r, int x, int y, int v)
	{
		if (x > r || y < l) return;
		if (x <= l && r <= y){return push(p, l, r, v), void();}
		pushdown(p, l, r);
		if (x <= mid) update(ls, l, mid, x, y, v);
		if (y > mid) update(rs, mid + 1, r, x, y, v);
		pushup(p);
	}
	int find(int p, int l, int r, int x)
	{
		if (mn[p] > x) return A + 1;
		if (l == r) return l;
		if (mn[ls] <= x) return find(ls, l, mid, x);
		return find(rs, mid + 1, r, x);
	}
}T;

int main()
{
	freopen("card.in", "r", stdin), freopen("card.out", "w", stdout);
	read(n), read(A), read(B), read(C);
	for(RE int i = 1; i <= n; i++) read(p[i].a), read(p[i].b), read(p[i].c);
	sort(p + 1, p + n + 1, cmpA), suf[A + 1] = 1;
	for(RE int i = A, j = 1; i; i--)
	{
		suf[i] = suf[i + 1];
		while (j <= n && p[j].a >= i) suf[i] = max(suf[i], p[j].b + 1), ++j;
	}
	T.build(1, 1, A);
	for(RE int i = 1; i <= n; i++) add(p[i].c, i);
	for(RE int i = C; i; i--)
	{
		for(RE int j = h[i], k; j; j = e[j].nxt)
			T.update(1, 1, A, 1, p[k = e[j].to].a, B + 1), T.update(1, 1, A, T.find(1, 1, A, p[k].b), A, p[k].b + 1);
		ans += (LL)B * A + A - T.sum[1];
	}
	printf("%lld\n", ans);
}

\(\text{T3 zero}\) 方形的零

先咕了。。。