[LOJ3192] 「ROI 2019 Day2」課桌
阿新 • • 發佈:2021-10-15
噔噔蹬蹬~
前言
我收回上一篇題解的話,這題我自己做複雜度鐵定優化不下去,本地最多 \(94pts\)。
但是沒有時間,只拿了 \(12pts\),虧大了。
題目
講解
這題其實就利用一個東西:單調性。
我個人認為這題的結論應該比較顯然。
排除掉完全沒用的桌子(範圍被其它桌子完全包含),假如我們已經選好了桌子,將桌子按左端點排序後,每組的學生也應該按高度從低到高坐到座位上。
此時我們不再把學生分為 \(m\) 組,因為組內沒什麼聯絡,我們將坐在同一張桌子的同學視為一組,共有 \(2m\) 組,每組 \(n\) 個同學。
每組同學使用同一張桌子,這 \(2m\) 組使用的桌子按左端點單調不降。
然後我們直接對新定義的組分治,求出中間那個組的貢獻之後,由於桌子也是單調的,往兩邊分治就好了。
用飄飄蛋的話來說:實現的時候要精細一點,用 two-pointer
可以顯著降低複雜度。
時間複雜度 \(O((k+nm)\log_2n)\)。
程式碼
不精細的實現
//12252024832524 #include <bits/stdc++.h> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 200005; const LL INF = 1ll << 60; int m,n,k; int o[MAXN << 1]; bool tag[MAXN]; struct desk { int l,r; bool operator < (const desk &px)const{ if(l^px.l) return l < px.l; return r > px.r; } }d[MAXN]; vector<desk> a[MAXN]; LL Read() { LL x = 0,f = 1; char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} LL Get(desk stu,desk des)//student & desk { LL ret = 0; if(stu.l < des.l) ret += des.l - stu.l; if(stu.l > des.r) ret += stu.l - des.r; if(stu.r < des.l) ret += des.l - stu.r; if(stu.r > des.r) ret += stu.r - des.r; return ret; } LL solve(int sl,int sr,int dl,int dr)//student lr,desk lr,好像是個暴力吧? LOJ有78 (Ofast) { if(sl > sr) return 0; LL ret = 0; if(dl == dr) { for(int i = 1;i <= m;++ i) for(int j = sl;j <= sr;++ j) ret += Get(a[i][j],d[dl]); return ret; } int mid = (sl+sr) >> 1,B = dl; LL MIN = INF; for(int i = dl;i <= dr;++ i) { LL cur = 0; for(int j = 1;j <= m;++ j) cur += Get(a[j][mid],d[i]); if(cur < MIN) B = i,MIN = cur; } return MIN+solve(sl,mid-1,dl,B)+solve(mid+1,sr,B,dr); } int main() { // freopen("party.in","r",stdin); // freopen("party.out","w",stdout); m = Read(); n = Read(); k = Read(); for(int i = 1;i <= k;++ i) d[i].l = Read(),d[i].r = Read(); sort(d+1,d+k+1); int R = 0; for(int i = 1;i <= k;++ i) { if(R >= d[i].r) tag[i] = 1; R = Max(R,d[i].r); } int kk = k; k = 0; for(int i = 1;i <= kk;++ i) if(!tag[i]) d[++k] = d[i]; for(int i = 1;i <= m;++ i) { for(int j = 0;j < (n<<1);++ j) o[j] = Read(); sort(o,o+(n<<1)); for(int j = 0;j < (n<<1);j += 2) a[i].emplace_back(desk{o[j],o[j+1]}); } Put(solve(0,n-1,1,k),'\n'); return 0; }
精細的實現
//12252024832524 #include <bits/stdc++.h> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 200005; const LL INF = 1ll << 60; int m,n,k; int o[MAXN << 1]; bool tag[MAXN]; struct desk { int l,r; bool operator < (const desk &px)const{ if(l^px.l) return l < px.l; return r > px.r; } }d[MAXN]; vector<desk> a[MAXN]; vector<int> fs[MAXN];//final students list LL Read() { LL x = 0,f = 1; char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} LL Get(int h,desk des)//student & desk { if(h < des.l) return des.l - h; if(h > des.r) return h - des.r; return 0; } LL pre[MAXN << 1]; LL Query(int l,int r) { if(l > r) return 0; LL ret = pre[r]; if(!l) return ret; return ret - pre[l-1]; } LL solve(int sl,int sr,int dl,int dr)//student lr,desk lr,O((k+nm)log_2n) { if(sl > sr) return 0; LL cur = 0,MIN = INF; int lid = 0,rid = 0,B = dl,mid = (sl+sr) >> 1; for(int i = 0;i < (m<<1);++ i) pre[i] = ((i ? pre[i-1] : 0) + fs[mid][i]); for(int i = dl;i <= dr;++ i) { while(lid < (m<<1) && fs[mid][lid] < d[i].l) ++lid; while(rid < (m<<1) && fs[mid][rid] <= d[i].r) ++rid; cur = 1ll * d[i].l * lid - Query(0,lid-1) + Query(rid,(m<<1)-1) - 1ll * ((m<<1)-rid) * d[i].r; if(cur < MIN) MIN = cur,B = i; } return MIN+solve(sl,mid-1,dl,B)+solve(mid+1,sr,B,dr); } int main() { // freopen("party.in","r",stdin); // freopen("party.out","w",stdout); m = Read(); n = Read(); k = Read(); for(int i = 1;i <= k;++ i) d[i].l = Read(),d[i].r = Read(); sort(d+1,d+k+1); int R = 0; for(int i = 1;i <= k;++ i) { if(R >= d[i].r) tag[i] = 1; R = Max(R,d[i].r); } int kk = k; k = 0; for(int i = 1;i <= kk;++ i) if(!tag[i]) d[++k] = d[i]; for(int i = 1;i <= m;++ i) { for(int j = 0;j < (n<<1);++ j) o[j] = Read(); sort(o,o+(n<<1)); for(int j = 0;j < (n<<1);j += 2) fs[j >> 1].emplace_back(o[j]),fs[j >> 1].emplace_back(o[j+1]); } for(int i = 0;i < n;++ i) sort(fs[i].begin(),fs[i].end()); Put(solve(0,n-1,1,k),'\n'); return 0; }