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;
}