contest-20191021

文化课读的真开心

回来竞赛

 

 

假人

sol

根据不等式有 abs(a-b)+abs(b-c)>=abs(a-c)

那么每一个都会选。

可以发现每一段只会选在端点上(否则移到端点更优)。

那么dp f[i][0/1]表示前i个选在上/下端点的最大值。

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
using namespace std;
int n,a[maxn][2];
long long s1,s2,f[maxn][2];
int main()
{
    freopen("arachne.in","r",stdin);
    freopen("arachne.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i][0],&a[i][1]);
    for(int i=2;i<=n;i++){
        s1=max(abs(a[i][0]-a[i-1][1])+f[i-1][1],abs(a[i][0]-a[i-1][0])+f[i-1][0]);
        s2=max(abs(a[i][1]-a[i-1][1])+f[i-1][1],abs(a[i][1]-a[i-1][0])+f[i-1][0]);
        f[i][0]=s1;f[i][1]=s2;
    }
    cout<<max(f[n][0],f[n][1])<<endl;
    return 0;
}
View Code

 

愚者

sol

考虑把点按权值大到小加入,用并查集维护联通快大小,那么每次加入的一定是最小值。
把式子展开,发现它形如y=kx+b.

每次得到一组(k,b)

对这些直线构出下凸壳,线性处理ans

100%数据范围小于部分分范围是什么鬼,差评投诉

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 300005
#define ll long long
using namespace std;
int n,m,Q,head[maxn],tot;
int f[maxn],sz[maxn],flag[maxn];
ll ans[maxn];
struct line{
    ll a,b;
}s[maxn],li[maxn],l[maxn],q[maxn];
struct node{
    int v,nex;
}e[maxn];
void add(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
bool cmp(line A,line B){return A.a>B.a;}
bool dmp(line A,line B){return A.a<B.a||(A.a==B.a&&A.b<B.b);}
int getf(int k){return f[k]==k?k:f[k]=getf(f[k]);}
double C(line A,line B){
    return (double)(B.b-A.b)/(double)(A.a-B.a);
}
int main()
{
    cin>>n>>m>>Q;
    for(int i=1;i<=n;i++){
        scanf("%lld",&s[i].a),s[i].b=i;
        f[i]=i;sz[i]=1;
    }
    for(int i=1,t1,t2;i<=m;i++){
        scanf("%d%d",&t1,&t2);
        add(t1,t2);add(t2,t1);
    }
    for(int i=1;i<=Q;i++)scanf("%lld",&q[i].a),q[i].b=i;
    sort(s+1,s+n+1,cmp);
    for(int x=1;x<=n;x++){
        flag[s[x].b]=1;
        for(int i=head[s[x].b];i;i=e[i].nex){
            if(flag[e[i].v]){
                int fv=getf(e[i].v);
                if(fv!=s[x].b)f[fv]=s[x].b,sz[s[x].b]+=sz[fv];
            }
        }
        li[x].a=sz[s[x].b];li[x].b=s[x].a*sz[s[x].b];
    }
    sort(li+1,li+n+1,dmp);sort(q+1,q+Q+1,dmp);
    int j=1;
    int tp=0;
    for(int i=1;i<=n;i++){
        if(li[i].a==li[i+1].a&&li[i].b<=li[i+1].b)continue;
        while(tp>1&&C(l[tp-1],l[tp])>C(l[tp-1],li[i]))tp--;
        l[++tp]=li[i];
    }
    for(int i=1;i<=tp;i++){
        
        double cr;
        if(i<tp)cr=C(l[i],l[i+1]);
        else cr=1e7;
        for(;j<=Q&&(double)q[j].a<cr;j++)ans[q[j].b]=l[i].a*q[j].a+l[i].b;
    }
    for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
    return 0;
}
View Code

 

拙者

sol

40% 贪心从前往后再从后往前取即可

20% (1,2) 线段树维护最小值

100%

考虑第一次从左往右的修改。

把+1看成向上,-1看成向下,这个序列看成折现

每一个点的最终位置是他减他之前的最小值,也就是把他之前的最小值提到0(水平位置)。

那么考虑维护区间最大值,最小值,极差,总和。

从前往后是答案是 max(-最小值,0)

从前往后是max(极差-(sum-Min))

极差就是最高点,sum-Min为最后一个点的位置。

60% 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 200005
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
using namespace std;
int n,q,a[maxn],b[maxn];
char ch[maxn];
struct node{
    int v,bj;
}tr[maxn*4];
node wh(node A,node B){
    node C;
    C.sum=A.sum+B.sum;
    C.mi=min(A.mi,A.sum+B.mi);
    C.ma=max(A.ma,A.sum+B.ma);
    C.d=max(max(A.d,B.d),A.sum+B.ma-A.mi);
    return C;
}
void build(int k,int l,int r){
    if(l==r){tr[k].sum=tr[k].ma=tr[k].mi=a[l];tr[k].d=0;return;}
    build(ls,l,mid);build(rs,mid+1,r);
    tr[k]=wh(tr[ls],tr[rs]);
}
void upd(int k,int l,int r,int pl){
    if(l==r){
        tr[k].sum=tr[k].ma=tr[k].mi=a[l];
        return;
    }
    if(pl<=mid)upd(ls,l,mid,pl);
    else upd(rs,mid+1,r,pl);
    tr[k]=wh(tr[ls],tr[rs]);
}
node ask(int k,int l,int r,int li,int ri){
    if(l>=li&&r<=ri)return tr[k];
    if(ri<=mid)return ask(ls,l,mid,li,ri);
    if(li>mid)return ask(rs,mid+1,r,li,ri);
    return wh(ask(ls,l,mid,li,ri),ask(rs,mid+1,r,li,ri));
}

void wh(int k){
    tr[k].v=min(tr[ls].v,tr[rs].v);
}
void build(int k,int l,int r){
    if(l==r){tr[k].v=b[l];return;}
    build(ls,l,mid);build(rs,mid+1,r);
    wh(k);
}
void upd(int k,int v){
    tr[k].bj+=v;tr[k].v+=v;
}
void down(int k){
    if(tr[k].bj!=0){
        upd(ls,tr[k].bj);upd(rs,tr[k].bj);
        tr[k].bj=0;
    }
}
void add(int k,int l,int r,int li,int ri,int v){
    if(l>=li&&r<=ri){
        upd(k,v);return;
    }
    down(k);
    if(li<=mid)add(ls,l,mid,li,ri,v);
    if(ri>mid)add(rs,mid+1,r,li,ri,v);
    wh(k);
}
int ask(int k,int l,int r,int li,int ri){
    if(li==0)return 0;
    if(l>=li&&r<=ri)return tr[k].v;
    down(k);
    int Min=1e9;
    if(li<=mid)Min=min(Min,ask(ls,l,mid,li,ri));
    if(ri>mid)Min=min(Min,ask(rs,mid+1,r,li,ri));
    return Min;
}
int main()
{
    cin>>n;scanf(" %s",ch+1);
    for(int i=1;i<=n;i++){
        a[i]=(ch[i]=='(')?1:-1;
    }
    if(n<=1000){
        scanf("%d",&q);
        for(int I=1,op,l,r;I<=q;I++){
            scanf("%d",&op);
            if(op==1)scanf("%d",&l),a[l]=-a[l];
            else {
                scanf("%d%d",&l,&r);
                if(op==2){
                    int tmp=0,ans=0;
                    for(int i=l;i<=r;i++){
                        b[i]=a[i];
                        if(tmp+b[i]<0)b[i]=0,ans++;
                        tmp+=b[i];
                    }
                    printf("%d\n",ans);
                }
                else {
                    int tmp=0,ans=0;
                    for(int i=l;i<=r;i++){
                        b[i]=a[i];
                        if(tmp+b[i]<0)b[i]=0,ans++;
                        tmp+=b[i];
                    }
                    tmp=0;
                    for(int i=r;i>=l;i--){
                        if(tmp+b[i]<0)b[i]=0,ans++;
                        tmp+=b[i];
                    }
                    printf("%d\n",ans);
                }
            }
        }
    }
    else {

        for(int i=1;i<=n;i++)b[i]=b[i-1]+a[i];
        build(1,1,n);
        scanf("%d",&q);
        for(int I=1,op,l,r;I<=q;I++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d",&l),add(1,1,n,l,n,-2*a[l]);
                a[l]=-a[l];
            }
            else {
                scanf("%d%d",&l,&r);
                if(op==2){
                    int x=ask(1,1,n,l-1,l-1),y=ask(1,1,n,l,r);
                    printf("%d\n",max(x-y,0));
                }
            }
        }
    }
    return 0;
}
View Code

 

100%

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1|1
#define maxn 200005
using namespace std;
int n,q,a[maxn];
char ch[maxn];
struct node{
    int ma,mi,sum,d;
}tr[maxn*4];

node wh(node A,node B){
    node C;
    C.sum=A.sum+B.sum;
    C.mi=min(A.mi,A.sum+B.mi);
    C.ma=max(A.ma,A.sum+B.ma);
    C.d=max(max(A.d,B.d),A.sum+B.ma-A.mi);
    return C;
}
void build(int k,int l,int r){
    if(l==r){tr[k].sum=a[l];tr[k].ma=max(a[l],0);tr[k].mi=min(a[l],0);tr[k].d=0;return;}
    build(ls,l,mid);build(rs,mid+1,r);
    tr[k]=wh(tr[ls],tr[rs]);
}
void upd(int k,int l,int r,int pl){
    if(l==r){
        tr[k].sum=a[l];tr[k].ma=max(a[l],0);tr[k].mi=min(a[l],0);tr[k].d=0;
        tr[k].d=0;
        return;
    }
    if(pl<=mid)upd(ls,l,mid,pl);
    else upd(rs,mid+1,r,pl);
    tr[k]=wh(tr[ls],tr[rs]);
}
node ask(int k,int l,int r,int li,int ri){
    if(l>=li&&r<=ri)return tr[k];
    if(ri<=mid)return ask(ls,l,mid,li,ri);
    if(li>mid)return ask(rs,mid+1,r,li,ri);
    return wh(ask(ls,l,mid,li,ri),ask(rs,mid+1,r,li,ri));
}
int main()
{
    cin>>n;scanf(" %s",ch+1);
    for(int i=1;i<=n;i++){
        a[i]=(ch[i]=='(')?1:-1;
    }
    build(1,1,n);
    scanf("%d",&q);int tp=0;
    for(int I=1,op,l,r;I<=q;I++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&l);a[l]=-a[l];
            upd(1,1,n,l);
        }
        else {
            scanf("%d%d",&l,&r);
            if(op==2){
                node ans=ask(1,1,n,l,r);
                printf("%d\n",max(-ans.mi,0));
            }
            else {
                node ans=ask(1,1,n,l,r);
                int sum=max(-ans.mi,0)+max(ans.d-(ans.sum-ans.mi),0);
                printf("%d\n",sum);
            }
        }
    }
    return 0;
}
/*
4
(())
1
3 1 4
*/
View Code

 

注意事项:

1.若查询l-1要特判0

2.修改a[l]外面也要改

3.区间最小值、最大值都要和0取,因为基准是0

posted @ 2019-10-21 17:18  liankewei123456  阅读(180)  评论(0编辑  收藏  举报