AtCoder Grand Contest 040 题解

传送门

为什么会这么晚……打不了了……

\(A\)

把所有山谷当做\(0\)就行了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=5e5+5;
char s[N];int a[N],n,mn;ll res;
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%s",s+1),n=strlen(s+1)+1;
    s[0]='>',s[n]='<';
    fp(i,1,n)a[i]=(s[i-1]=='>'&&s[i]=='<')?0:-1;
    fp(i,1,n)if(a[i]==0){
//      printf("%d %d\n",i,a[i]);
        for(R int j=i+1;j<=n&&s[j-1]=='<';++j)cmax(a[j],a[j-1]+1);
        for(R int j=i-1;j&&s[j]=='>';--j)cmax(a[j],a[j+1]+1);
    }
    fp(i,1,n)res+=a[i];
    printf("%lld\n",res);
    return 0;
}

\(B\)

傻掉了,自已\(yy\)了一个觉得很对的莫名其妙\(WA\)三个点而且死活调不对,自闭了

正解:把最大的左端点和最小的右端点取出来,如果这两个在同一个集合那么另一个显然扔一个长度最长的线段就行了,如果不在一个集合,那么我们把所有线段按照和两个分别在同一个集合可以得到的长度\(sort\)一下搞一搞后缀最小值就行了

//quming
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;
typedef pair<int,int> pi;
pi L[N],a[N];int b[N],suf[N],n,res,mxl,mxr,len;
int main(){
    scanf("%d",&n);
    mxl=mxr=1,len=0;
    fp(i,1,n){
        scanf("%d%d",&L[i].fi,&L[i].se),++L[i].se;
        cmax(len,L[i].se-L[i].fi);
        if(L[i].fi>L[mxl].fi)mxl=i;
        if(L[i].se<L[mxr].se)mxr=i;
    }
    cmax(res,len+max(0,L[mxr].se-L[mxl].fi));
    if(mxl==mxr)return printf("%d\n",res),0;
    fp(i,1,n){
        a[i].fi=max(L[i].se-L[mxl].fi,0);
        a[i].se=i;
        b[i]=max(L[mxr].se-L[i].fi,0);
    }
    sort(a+1,a+1+n),reverse(a+1,a+1+n);
    suf[n+1]=inf;
    fd(i,n,1)suf[i]=min(suf[i+1],b[a[i].se]);
    fp(i,1,n-1)cmax(res,a[i].fi+suf[i+1]);
    printf("%d\n",res);
    return 0;
}

我的思路:如果线段\(A\)包含线段\(B\),如果\(B\)在集合\(S\)中,那么除非\(T\)为空,否则把\(A\)扔过去一定不会使答案变优,且因为已经有\(B\)\(A\)留在\(S\)中不会使答案变劣,那么我们把所有这样的线段\(A\)去掉,剩下的是若干互不包含的线段,然后把所有线段按左端点排序,那么\(S,T\)一定是前缀和后缀,搞一搞就行了,最后特判一下\(T\)中只有一个\(A\)的情况

不知道有没有哪位老鸽帮咱看看到底是哪里出问题了QAQ

//quming
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
typedef pair<int,int> pi;
int n,res,Pre[N],suf[N],st[N],ins[N],top;pi a[N],L;
inline pi operator +(const pi &a,const pi &b){return pi(b.fi,a.se);}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d",&n);
    fp(i,1,n)scanf("%d%d",&a[i].fi,&a[i].se);
    sort(a+1,a+1+n,[](const pi &a,const pi &b){
        return a.fi==b.fi?a.se>b.se:a.fi<b.fi;
    });
    fp(i,1,n){
        while(top&&a[st[top]].se>=a[i].se)--top;
        st[++top]=i;
    }
    fp(i,1,top)ins[st[i]]=1;
    L=a[st[1]],Pre[1]=L.se-L.fi+1;
    fp(i,2,top){
        L=L+a[st[i]];if(L.se<L.fi)break;
        Pre[i]=L.se-L.fi+1;
    }
    L=a[st[top]],suf[top]=L.se-L.fi+1;
    fd(i,top-1,1){
        L=a[st[i]]+L;if(L.se<L.fi)break;
        suf[i]=L.se-L.fi+1;
    }
    fp(i,1,top-1)cmax(res,Pre[i]+suf[i+1]);
    fp(i,1,n)if(!ins[i])cmax(res,Pre[top]+a[i].se-a[i].fi+1);
    printf("%d\n",res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yuanquming/p/11790167.html