JZOJ 2022.04.05【省選組】聯訓模擬22
阿新 • • 發佈:2022-04-06
總結
一不小心就掛了。。。
題還挺好做的,畢竟是 \(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\)
那麼就可以 \(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\)
於是可以改為區間賦值操作
\(\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}\) 方形的零
先咕了。。。