csp-s真题题解

csp题目讲解

csp-s 2021

P7913 [CSP-S 2021] 廊桥分配

时隔3个月我都以为忘没了,口胡了发现是一样的思路,非常厉害啊,那就不管了放个口胡解法得了。

latex我也不改了就这样吧。

依次处理国内部和国际部,将飞机按抵达时间排序,ans[i]存第i个机场库能存放的飞机,处理国内部,一个飞机着落了,如果没有任何飞机,直接降落机场库,ans[1]++,如果有飞机那就叠一层,ans[2]++,再加入一个,发现第一个离开了,此时是ans[1]++,再来一个但没有飞机起飞,ans[3]++,以此类推,然后国际部也这么做,统计答案时候,for(int i=1;i<=k;i++)ans[i]+=ans[i-1]是为了统计,最后for(int i=0;i<=n;i++) mx=max(mx,ans1[i]-ans2[n-i],然后输出mx,感觉非常可行

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
#define pi pair<int,int>
int n,m1,m2;

struct ss{
	int l,r;
}a[N],b[N];

int ans1[N],ans2[N];

bool cmp(ss g,ss h){
	return g.l<h.l;
}

void solve(ss *s,int t,int *ans){
	priority_queue<pi,vector<pi>,greater<pi> > q;
	priority_queue<int,vector<int>,greater<int> > p;
	
	for(int i=1;i<=n;i++){
		p.push(i);
	}
	
	for(int i=1;i<=t;i++){
		while(!q.empty()&&q.top().first<=s[i].l){
			p.push(q.top().second);
			q.pop();
		}
		if(p.empty()){
			continue;
		}
		int k=p.top();
		p.pop();
		ans[k]++;
		q.push({s[i].r,k});
	}
	
	for(int i=1;i<=n;i++){
		ans[i]+=ans[i-1];
	}
}

signed main(){
    ios::sync_with_stdio(false);
	cin.tie(nullptr); 
	
	cin>>n>>m1>>m2;
	
	for(int i=1;i<=m1;i++){
		cin>>a[i].l>>a[i].r;
	}
	
	for(int i=1;i<=m2;i++){
		cin>>b[i].l>>b[i].r;
	}
	
	sort(a+1,a+m1+1,cmp);
	sort(b+1,b+m2+1,cmp);
	
	solve(a,m1,ans1);
	solve(b,m2,ans2);

	int mx=0;

	for(int i=0;i<=n;i++){
		mx=max(mx,ans1[i]+ans2[n-i]);
	}
	cout<<mx;
    return 0;
}

P7915 [CSP-S 2021] 回文

大佬博客

在算法实现上可以去大佬里看,我只会口胡下并写下点小细节。

因为是2n个数必定有重复,画一下图发现回文序列的末尾一定是原数列中间的连续的区间,此时我们就可以枚举这个中间的区间来判断是否合法,而且从后向前选区间一定是最小字典序,因为这样右边的数就更少,所有R操作也更少,我们判断合法的时候也先判断右边相同也是为了使R尽可能集中在中间使两边的L更多,从而使字典序更小。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;

int n;
int a[N];

int l[N],r[N],k;
char ans[N];
int vis[N],cnt;

signed main(){
    ios::sync_with_stdio(false);
	cin.tie(nullptr); 
	
	int t;
	cin>>t;
	
	while(t--){
		cin>>n;
		memset(vis,0,sizeof vis);
		memset(a,0,sizeof a);
		k=0;
		cnt=0;
		for(int i=1;i<=2*n;i++){
			cin>>a[i];
			if(vis[a[i]]==0){
				cnt++;
			}
			vis[a[i]]++;
			if(i>n){
				vis[a[i-n]]--;
				if(vis[a[i-n]]==0){
					cnt--;
				}
			}
			if(cnt==n){
				l[++k]=i-n+1;
				r[k]=i;
			}
		}
		int flag=0;
		
		for(int q=k;q>=1;q--){
			memset(ans,0,sizeof ans);
			int now=0;
			int ll=l[q],rr=r[q],sl=l[q]-1,sr=r[q]+1;
			
			while(ll<=rr){
				
				if(a[sr]==a[ll]){
					ans[n-now]='R';
					ans[n+now+1]='L';
					sr++;
					ll++;
					now++;
				}
				else if(a[sr]==a[rr]){
					ans[n-now]='R';
					ans[n+now+1]='R';
					sr++;
					rr--;
					now++;
				}
				else if(a[sl]==a[ll]){
					ans[n-now]='L';
					ans[n+now+1]='L';
					ll++;
					sl--;
					now++;
				}
				else if(a[sl]==a[rr]){
					ans[n-now]='L';
					ans[n+now+1]='R';
					rr--;
					sl--;
					now++;
				}
				else{
					break;	
				}
			}
			if(now==n){
				flag=1;
				break;
			}
		}
		if(flag==0){
			cout<<-1<<"\n";
		}
		else{
			for(int i=1;i<=2*n;i++){
				cout<<ans[i];
			}
			cout<<"\n";
		}
	}

    return 0;
}

csp-s 2022

P8817 [CSP-S 2022] 假期计划

大神题解

唉,还是自己想不出的题,马上要考试了,怎么办,非常慌,但我还是有必要记一下题解吧。

大神已经讲的非常清楚,口胡下做法得了,数据范围支持到 \(n^2\) 所以可能会排除些假做法,因为路径有四个点,所以贪心地看,选择了前三个a,b,c后就只能选一个最大的d了,同样的选择了b,c,d后就只能选最大的a了,所以我们枚举b,c同时找最大的a,d,但是可能会重点,所以要选出第二大和第三大的来保证没有相同的点,然后进行搭配选择即可。

P8818 [CSP-S 2022] 策略游戏

学习笔记

感觉非常复杂?对于现在的我还是有深度的,首先第一个大坑就是并不需要真的求出c矩阵,这个题意就是让你在区间中选数,但要求乘积最大,所以要分讨。

你假定 \(a_i\ge0\),那这时如果 \(min(b_i)\ge0\)\(max(a_i)\),否则取 \(min(a_i\ge0)\),相反的,假定\(a_i<0\),那这时如果 \(max(b_i)\ge0\)\(max(a_i)\),否则取 \(max(a_i<0)\)

这就是贪心的思想,感觉非常有深度(菜),然后就需要维护6个ST表,非常糟糕啊,然后就没有然后了,你就慢慢维护去吧。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;

int a[N],b[N],lg[N];
int n,m,q;

int mxa[N][20];
int mia[N][20];
int rmxa[N][20];
int rmia[N][20];

int mxb[N][20];
int mib[N][20];

int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m>>q;
	lg[1]=0;
	for(int i=2;i<=max(n,m);i++){
		lg[i]=lg[i>>1]+1;
	}
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
		mxa[i][0]=mia[i][0]=a[i];
		rmia[i][0]=0<=a[i]?a[i]:INT_MAX;//正数中取最小,没正数取intmin标记为无 
		rmxa[i][0]=a[i]<0?a[i]:INT_MIN;//负数中取最大,没负数取intmax标记为无 
	}
	
	for(int i=1;i<=m;i++){
		cin>>b[i];
		mxb[i][0]=mib[i][0]=b[i];
	}
	
	for(int j=1;j<=lg[n];j++){
		for(int i=1;i<=n-(1<<j)+1;i++){
			int p=i+(1<<(j-1));
			mxa[i][j]=max(mxa[i][j-1],mxa[p][j-1]);
			rmxa[i][j]=max(rmxa[i][j-1],rmxa[p][j-1]);
			mia[i][j]=min(mia[i][j-1],mia[p][j-1]);
			rmia[i][j]=min(rmia[i][j-1],rmia[p][j-1]);
		}
	}
	
	for(int j=1;j<=lg[m];j++){
		for(int i=1;i<=n-(1<<j)+1;i++){
			int p=i+(1<<(j-1));
			mxb[i][j]=max(mxb[i][j-1],mxb[p][j-1]);
			mib[i][j]=min(mib[i][j-1],mib[p][j-1]);
		}
	}
	
	while(q--){
		int la,ra,lb,rb;
		cin>>la>>ra>>lb>>rb;
		int x=lg[ra-la+1],y=lg[rb-lb+1];
		int pa=ra-(1<<x)+1,pb=rb-(1<<y)+1;
		
		int mmxa=max(mxa[la][x],mxa[pa][x]);
		int rmmxa=max(rmxa[la][x],rmxa[pa][x]);
		
		int mmia=min(mia[la][x],mia[pa][x]);
		int rmmia=min(rmia[la][x],rmia[pa][x]);
		
		int mmxb=max(mxb[lb][y],mxb[pb][y]);
		int mmib=min(mib[lb][y],mib[pb][y]);
		
		long long ans=LONG_LONG_MIN;
		
		ans=max(ans,(ll)mmxa*(mmxa>=0?mmib:mmxb));
		ans=max(ans,(ll)mmia*(mmia>=0?mmib:mmxb));
		
		if(rmmxa!=INT_MIN){
			ans=max(ans,(ll)rmmxa*(rmmxa>=0?mmib:mmxb));
		} 
		if(rmmia!=INT_MAX){
			ans=max(ans,(ll)rmmia*(rmmia>=0?mmib:mmxb));
		}
		cout<<ans<<"\n";
	}

	return 0;
}

csp-s 2023

posted @ 2024-10-11 18:38  sad_lin  阅读(14)  评论(0编辑  收藏  举报