1. 程式人生 > 其它 >CSP 2021 總結

CSP 2021 總結

CSP 2021 總結

PJ

開題順序:1342

應該先做 T2 ,導致我 T2 直接看錯

T1、T3

T1 :直接推規律即可,考場的想法應該正確

T3 :好傢伙直接 map 走起

T2

最崩潰的來了 :\(5000\times8000=4e7\) 是吧,愣是給我看成了 \(4e8\)

然後想打插入排序(正解)騙分,發現插入排序不對,就直接 sort

。。。。。。。。

。。。。。。。。

。。。。。。。。

心 態 炸 裂

退役吧

T4

考試時想到雙鏈表,過了小資料,但沒過大資料

浪費了太多時間,導致了 T2 直接掛

總結

考試的心態不好,太急了,連 T1 都要好久才沉下心來想

今年的 pj 比較水,沒有說什麼沒想到。

但是程式碼實現弱 —— T4 掛了,並浪費大量時間

眼花繚亂——四千萬看成四億

TG

T1

直接列舉廊橋+堆,暴力 \(O(nm\log n)\)

正解:設 \(c_i\) 表示 \(i\) 個廊橋能停靠的飛機,則 \(ans=\max c_{1,i}+c_{2,n-i}\)

考慮到每一個廊橋加入都會使得飛機可以停靠。

\(c_i=c_{i-1}+x\) , 因為 \(c_0=0\) ,於是可以通過已知 \(c_{i-1}\) 推出 \(c_i\)

考慮求 \(x\) ,因為先到先得,原有的廊橋是被佔滿的,於是新加的廊橋只會影響沒有停廊橋的飛機

模擬,若當前飛機停靠的結束時間是 \(t\) ,每次查詢停靠開始時間最接近 \(t\)

的停靠,用一個 set 即可

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m1,m2,c1[N],c2[N],ans;
struct rg {
	int l,r;
    bool operator <(rg A) const {
        return l<A.l;
    }
}x[N],y[N];
set<rg>S;
set<rg>::iterator it;
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",&x[i].l,&x[i].r);
	for(int i=1;i<=m2;i++)scanf("%d%d",&y[i].l,&y[i].r);
	sort(x+1,x+m1+1);
	sort(y+1,y+m2+1);
    S.clear();
    for(int i=1;i<=m1;i++)S.insert(x[i]);
    for(int i=1,vl,p;i<=n;i++) {
        vl=p=0;
        while(1) {
            it=S.lower_bound((rg){p,0});
            if(it==S.end())break;
            ++vl,p=it->r,S.erase(it);
        }
        c1[i]=c1[i-1]+vl;
    }
    S.clear();
    for(int i=1;i<=m2;i++)S.insert(y[i]);
    for(int i=1,vl,p;i<=n;i++) {
        vl=p=0;
        while(1) {
            it=S.lower_bound((rg){p,0});
            if(it==S.end())break;
            ++vl,p=it->r,S.erase(it);
        }
        c2[i]=c2[i-1]+vl;
    }
    for(int i=0;i<=n;i++)
        ans=max(ans,c1[i]+c2[n-i]);
	printf("%d",ans);
} 

T2

區間 dp ,想到後直接放棄

T3

大模擬,對於第一個是 \(L\)\(R\) 分類討論

問題簡化為兩個棧,如何輪流彈出棧頂使序列是個迴文序列

可通過奇怪證明,發現若能彈出則一定可以彈出。

於是按照字典序列舉情況即可

考場就想到了正解,但是一些奇怪的錯誤被 hack 了

。。。。。。。。

。。。。。。。。

。。。。。。。。

心 態 炸 裂

退役吧

題解:這裡可以把棧變成雙端佇列,每次彈出一對相同的數,組成迴文

#include<bits/stdc++.h>
using namespace std;
const int N=500005;
int T,n,x[N<<1],fl,p,ans[N<<1];
struct que {
    int q[N<<1],l,r;
    inline void clear() { l=1,r=0; }
    inline void push(int a) { q[++r]=a; }
    inline int Fr() { return q[l]; }
    inline int Bk() { return q[r]; }
    inline bool empty() { return l>r; }
    inline void Pf() { ++l; }
    inline void Pb() { --r; }
    inline int Sz() { return r-l+1; }
}A,B;
void make(int op) {
	int p1=1,p2=n;
	if(op==1)++p1;
	else --p2;
    A.clear(),B.clear();
	for(int i=p-1;i>=p1;i--)A.push(x[i]);
    for(int i=p+1;i<=p2;i++)B.push(x[i]);
    for(int i=2;i<=n/2;i++) {
        if(A.empty() && B.empty())break;
        if(B.empty()) {
            if(A.Fr()!=A.Bk())
                return;
            ans[i]=ans[n-i+1]=1;
            A.Pb(),A.Pf();
        } else if(A.empty()) {
            if(B.Fr()!=B.Bk())
                return;
            ans[i]=ans[n-i+1]=2;
            B.Pb(),B.Pf();
        } else {
            if(A.Sz()>1 && A.Fr()==A.Bk())
                ans[i]=ans[n-i+1]=1,A.Pb(),A.Pf();
            else if(A.Bk()==B.Fr())
                ans[i]=1,ans[n-i+1]=2,A.Pb(),B.Pf();
            else if(A.Fr()==B.Bk())
                ans[i]=2,ans[n-i+1]=1,A.Pf(),B.Pb();
            else if(B.Sz()>1 && B.Fr()==B.Bk())
                ans[i]=ans[n-i+1]=2,B.Pb(),B.Pf();
            else return;
        }
	}
	fl=1;
}
int main() {
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n),n<<=1;
		for(int i=1;i<=n;i++) {
			scanf("%d",&x[i]);
		}
		ans[n]=1;
		fl=0;
		ans[1]=1;
		for(int i=2;i<=n;i++)
			if(x[i]==x[1]) {
				p=i; break;
			}
		make(1);
		if(!fl) {
			ans[1]=2;
			for(int i=1;i<n;i++)
				if(x[i]==x[n]) {
					p=i; break;
				}
			make(n);
		}
		if(!fl)puts("-1");
		else {
			for(int i=1;i<=n;i++) {
				if(ans[i]==1)putchar('L');
				else putchar('R');
			}
			puts("");
		}
	}
}

T4

What?

看懂大意後直接再見

總結

很好——暴力沒有掛,至少能有分

我* —— 實現上的失誤,還是程式碼實現能力差

大總結

  1. 程式碼實現能力弱
  2. 思維不夠發散,一些結論不難的題想不到
  3. 考試的心態不夠好,過於心急,導致半天一籌莫展

過去的都過去了,希望今年 noip 能拿到 50 分