CSP-S 2021
阿新 • • 發佈:2021-10-26
我們總是在注意錯過太多,卻不注意自己擁有多少。
T1:
考慮每次飛機獲得的編號機場是固定的。
而是否走上廊道只取決於其的編號機場小於廊道數。
那麼只要考慮計算編號。
那麼可以發現實際上一個二維偏序\(mex\)。
考慮一維排序,一維優先佇列,二分BIT \(mex\)。
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #define N 100005 int n,m1,m2; struct P{int l,r,op;}e[N]; bool cmp(P a,P b){return a.l < b.l;} bool operator < (P a,P b){return a.r > b.r;} int T[N]; #define lowbit(x) (x & -x) inline void add(int x,int p){ for(int i = x;i <= N - 1;i += lowbit(i)){ T[i] += p; } } inline int find(int x){ int ans = 0 ; for(int i = x;i;i -= lowbit(i)){ ans += T[i]; } return ans; } int lasin[N],lasout[N]; std::priority_queue<P>QWQ; #define mid ((l + r) >> 1) inline int mex(){ int l = 1,r = N; int ans = 0; while(l <= r){ if(find(mid) != mid) ans = mid,r = mid - 1; else l = mid + 1; } return ans; } inline void del1(){ std::sort(e + 1,e + m1 + 1,cmp); for(int i = 1;i <= m1;++i){ e[i].op = i; if(QWQ.size()) while(QWQ.size() && QWQ.top().r < e[i].l ) add(lasin[QWQ.top().op],-1),QWQ.pop(); lasin[i] = mex(); add(lasin[i],1); QWQ.push(e[i]); } std::sort(lasin + 1,lasin + m1 + 1); } inline void del2(){ for(int i = 1;i <= N;++i) T[i] = 0; while(QWQ.size()) QWQ.pop(); std::sort(e + 1,e + m2 + 1,cmp); for(int i = 1;i <= m2;++i){ e[i].op = i; while(QWQ.size() && QWQ.top().r < e[i].l ) add(lasout[QWQ.top().op],-1),QWQ.pop(); lasout[i] = mex(); add(lasout[i],1); QWQ.push(e[i]); } std::sort(lasout + 1,lasout + m2 + 1); } int ans; inline int Findin(int x){ int l = 0,r = m1; int ans = 0; while(l <= r){ if(lasin[mid] <= x) ans = mid,l = mid + 1; else r = mid - 1; } return ans; } inline int Findout(int x){ int l = 0,r = m2; int ans = 0; while(l <= r){ if(lasout[mid] <= x) ans = mid,l = mid + 1; else r = mid - 1; } return ans; } int main(){ // freopen("airport.in","r",stdin); // freopen("airport.out","w",stdout); scanf("%d%d%d",&n,&m1,&m2); for(int i = 1;i <= m1;++i) scanf("%d%d",&e[i].l,&e[i].r); del1(); for(int i = 1;i <= m2;++i) scanf("%d%d",&e[i].l,&e[i].r); del2(); for(int i = 0;i <= n;++i){ int x = i,y = n - i; int fx = Findin(x); int fy = Findout(y); ans = std::max(fx + fy,ans); } std::cout<<ans<<std::endl; }
T3
考慮列舉第一次是\(L,R\)。
不妨設是 \(L\) ,那麼取出第一位 \(x\) 以及和他顏色相同的另外一位 \(y\) 。
那麼顯然 \(y\) 一定是最後一次操作的。
那麼可以發現 \(y\) 已經把序列劃分開了,即下列的操作不可以跨越 \(y\) 這個位置。
即下一次操作的 \(y2\) 就是倒數第二次做的,那麼顯然是在劃分開的兩個序列斷點的一側,否則不合法。
考慮維護每次操作劃分序列的左右斷點,以及當前選到哪一個即可。
#include<iostream> #include<cstdio> #define ll long long #define N 500005 int T; int n; int a[N << 1]; int pos[N]; int flg; char ans[N]; inline void dfs(int l,int r,int ql,int qr,int dep){ if(dep == n){ for(int i = 0;i < n;++i) putchar(ans[i]); for(int i = n - 1;i >= 0;--i){ int now = (ans[i] == 'L' ? -- l : ++ r); int tmp = pos[a[now]] - now; if(tmp == ql) putchar('L'),++ql; else putchar('R'),--qr; } flg = 1; puts(""); } int tl = pos[a[l]] - l,tr = pos[a[r]] - r; if(tl == ql - 1 && ql - 1 > l){ans[dep] = 'L';dfs(l + 1,r,ql - 1,qr,dep + 1);return ;} else if(tl == qr + 1 && qr + 1 <= r){ans[dep] = 'L';dfs(l + 1,r,ql,qr + 1,dep + 1);return ;} if(tr == ql - 1 && ql - 1 >= l){ans[dep] = 'R';dfs(l,r - 1,ql - 1,qr,dep + 1);return ;} else if(tr == qr + 1 && qr + 1 < r){ans[dep] = 'R';dfs(l,r - 1,ql,qr + 1,dep + 1);return ;} } int main(){ freopen("palin.in","r",stdin); freopen("palin.out","w",stdout); scanf("%d",&T); while(T -- ){ scanf("%d",&n); for(int i = 1;i <= n;++i) pos[i] = 0; for(int i = 1;i <= n << 1;++i) scanf("%d",&a[i]),pos[a[i]] += i; int m = n << 1; flg = 0; ans[0] = 'L'; dfs(2,m,pos[a[1]] - 1,pos[a[1]] - 1,1); if(flg)continue; ans[0] = 'R'; dfs(1,m - 1,pos[a[m]] - m,pos[a[m]] - m,1); if(flg)continue; puts("-1"); } }