zoukankan      html  css  js  c++  java
  • 6.1 考试修改+总结

    QAQ 终于回到衡中了,昨天做了一个晚上的火车,所以没来的及补题解

    Em 儿童节快乐,撒花~~

    第一题

    NOIP难度?提到国王游戏都提醒你怎么做了

    直接裸上排序不等式化简一下就可以了

    具体化简过程就不再赘述了

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
     
    typedef long long LL;
    const int maxn=100010;
    int T,n;
    struct OP{
        LL a,b;
    }c[maxn];
    LL sum,ans,tmp;
     
    bool cmp(const OP &A,const OP &B){
        return A.a+B.b+max(A.b,B.a)<B.a+A.b+max(A.a,B.b);
    }
    void read(LL &num){
        num=0;char ch=getchar();
        while(ch<'!')ch=getchar();
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    }
     
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;++i)read(c[i].a),read(c[i].b);
            sort(c+1,c+n+1,cmp);
            sum=tmp=ans=0;
            for(int i=1;i<=n;++i){
                sum+=c[i].a;
                tmp=max(tmp,sum)+c[i].b;
            }ans=tmp;
            printf("%lld
    ",ans);
        }return 0;
    }
    

    第二题

    貌似是在湖南雅礼培训的时候考过的原题?

    现在看看是二维曼哈顿距离最小生成树的裸题

    随便写写之后在树上做一下倍增就可以了

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
     
    const int maxn=100010;
    const int oo=0x7fffffff;
    int n,m,cnt=0;
    int u,v;
    struct Edge{
        int u,v,w;
    }c[1000010];
    int tmp[maxn];
    int fa[maxn];
    int anc[maxn][20];
    int mx[maxn][20];
    int dep[maxn];
    int h[maxn],tot=0;
    struct edge{
        int to,next,w;
    }G[maxn<<1];
    struct pos{
        int x,y,id;
    }p[maxn],P[maxn];
    struct BIT{
        int mn,p;
    }t[maxn];
     
    int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
    bool cmp(const pos &A,const pos &B){
        if(A.x==B.x)return A.y<B.y;
        return A.x<B.x;
    }
    bool cmpdis(const Edge &A,const Edge &B){
        return A.w<B.w;
    }
    void add(int x,int y,int z){
        ++tot;G[tot].to=y;G[tot].next=h[x];G[tot].w=z;h[x]=tot;
    }
    int sqr(int x){return x*x;}
    int dis(int i,int j){
        return abs(P[i].x-P[j].x)+abs(P[i].y-P[j].y);
    }
    int lowbit(int x){return x&(-x);}
    void UPD(int x,int mn,int id){
        for(int i=x;i<=m;i+=lowbit(i)){
            if(t[i].mn>mn){
                t[i].mn=mn;t[i].p=id;
            }
        }return;
    }
    int ask(int x){
        int mn=oo,p=-1;
        for(int i=x;i>=1;i-=lowbit(i)){
            if(t[i].mn<mn){
                mn=t[i].mn;p=t[i].p;
            }
        }return p;
    }
    void make_Graph(){
        for(int flag=0;flag<4;++flag){
            if(flag==1||flag==3)for(int i=1;i<=n;++i)swap(p[i].x,p[i].y);
            else if(flag==2)for(int i=1;i<=n;++i)p[i].y=-p[i].y;
            for(int i=1;i<=n;++i)tmp[i]=p[i].x-p[i].y;
            sort(tmp+1,tmp+n+1);
            m=unique(tmp+1,tmp+n+1)-tmp-1;
            sort(p+1,p+n+1,cmp);
            for(int i=1;i<=n;++i)t[i].mn=oo,t[i].p=-1;
            for(int i=n;i>=1;--i){
                int Pos=lower_bound(tmp+1,tmp+m+1,p[i].x-p[i].y)-tmp;
                int cur=ask(Pos);
                if(cur!=-1){
                    ++cnt;
                    c[cnt].u=p[i].id;c[cnt].v=cur;
                    c[cnt].w=dis(c[cnt].u,c[cnt].v);
                }UPD(Pos,p[i].x+p[i].y,p[i].id);
            }
        }return;
    }
    void Kruscal(){
        sort(c+1,c+cnt+1,cmpdis);
        for(int i=1;i<=n;++i)fa[i]=i;
        for(int i=1;i<=cnt;++i){
            int d1=ufs(c[i].u),d2=ufs(c[i].v);
            if(d1!=d2){
                fa[d1]=d2;
                add(c[i].u,c[i].v,c[i].w);
                add(c[i].v,c[i].u,c[i].w);
            }
        }return;
    }
    void DFS(int u,int f){
        anc[u][0]=f;
        for(int i=h[u];i;i=G[i].next){
            int v=G[i].to;
            if(v==f)continue;
            mx[v][0]=G[i].w;
            dep[v]=dep[u]+1;
            DFS(v,u);
        }return;
    }
    void pre_LCA(){
        for(int i=1;i<=n;++i){
            for(int j=1;(1<<j)<=n;++j)anc[i][j]=-1,mx[i][j]=-oo;
        }
        for(int j=1;(1<<j)<=n;++j){
            for(int i=1;i<=n;++i){
                if(anc[i][j-1]!=-1){
                    int a=anc[i][j-1];
                    anc[i][j]=anc[a][j-1];
                    mx[i][j]=max(mx[i][j-1],mx[a][j-1]);
                }
            }
        }return;
    }
    int LCA(int p,int q){
        if(dep[p]<dep[q])swap(p,q);
        int log,ans=0;
        for(log=0;(1<<log)<=dep[p];++log);--log;
        for(int i=log;i>=0;--i){
            if(dep[p]-(1<<i)>=dep[q]){
                ans=max(ans,mx[p][i]);
                p=anc[p][i];
            }
        }
        if(p==q)return ans;
        for(int i=log;i>=0;--i){
            if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
                ans=max(ans,mx[p][i]);p=anc[p][i];
                ans=max(ans,mx[q][i]);q=anc[q][i];
            }
        }ans=max(ans,mx[p][0]);ans=max(ans,mx[q][0]);
        return ans;
    }
     
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y),p[i].id=i,P[i]=p[i];
        make_Graph();Kruscal();
        DFS(1,-1);pre_LCA();
        scanf("%d",&m);
        while(m--){
            scanf("%d%d",&u,&v);
            if(u==v){printf("0
    ");continue;}
            printf("%d
    ",LCA(u,v));
        }return 0;
    }
    

    第三题

    第三题失误好大。。一开始看题第一感dp,然后就陷在dp中拔不出来了

    这道题目最大的性质就是一个点只能增加不能减少

    如果可以减少的话就是只能写架设电话线那种O(n*a)的dp了

    我们考虑每个点只能增加,那么一个点当且仅当左右都比他高的时候增加才是有意义的

    但是一个点的高度增加之后可能会对其他点是否增加产生影响

    不难发现只有高度比这个点小的点增加才会对这个点产生影响

    那么我们把点从小到大排序依次增加就可以了

    问题就转化成了如何O(1)的计算要增加多少以及代价

    然后考虑每一步的收益,拆掉x^2变成每一步是2*base+1(base是之前增高的次数)

    用并查集维护联通块内的sigma(base)就可以了,化简一下式子就可以O(1)判断了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
     
    const int maxn=100010;
    const int oo=0x7fffffff/3;
    typedef long long LL;
    int cnt;
    LL n,c,ans;
    LL Num,mx,sz;
    LL a[maxn];
    LL sum[maxn];
    int pre[maxn],nxt[maxn];
    int L[maxn],R[maxn];
    int val[maxn];
    int fa[maxn];
    struct OP{
        int v,id;
    }t[maxn];
    bool cmp(const OP &A,const OP &B){return A.v<B.v;}
    int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);}
    void del(int x){pre[nxt[x]]=pre[x];nxt[pre[x]]=nxt[x];}
     
    int main(){
        scanf("%lld%lld",&n,&c);
        for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
        a[0]=oo;cnt=0;
        for(int i=1;i<=n;++i){
            if(a[i]!=a[i-1]){
                ++cnt;
                pre[cnt]=cnt-1;
                nxt[cnt]=cnt+1;
                L[cnt]=i;R[cnt]=i;
                val[cnt]=a[i];
            }else R[cnt]++;
        }nxt[0]=1;pre[cnt+1]=cnt;
        for(int i=1;i<=cnt;++i)fa[i]=i,t[i].v=val[i],t[i].id=i;
        fa[0]=0;fa[cnt+1]=cnt+1;
        sort(t+1,t+cnt+1,cmp);
        for(int i=1;i<cnt;++i){
            int now=ufs(t[i].id);
            Num=2;sz=R[now]-L[now]+1;mx=0;
            int l=ufs(pre[now]),r=ufs(nxt[now]);
            if(l==0||r==cnt+1){
                Num=1;
                if(l==0)mx=val[r]-val[now];
                else mx=val[l]-val[now];
            }else mx=min(val[l],val[r])-val[now];
            if(mx<=0){continue;}
            LL tmp=(Num*c-2*sum[now]-sz)/(2*sz);
            if(2*sum[now]+sz>Num*c)tmp=-1;
            if(tmp>=mx-1){
                ans=ans+mx*mx*sz+2*mx*sum[now];
                sum[now]+=mx*sz;
                val[now]+=mx;
                if(val[now]==val[l]&&val[now]==val[r]){
                    sum[now]+=sum[l]+sum[r];
                    L[now]=L[l];R[now]=R[r];
                    fa[l]=now;fa[r]=now;
                    del(l);del(r);
                }else if(val[now]==val[l]){
                    sum[now]+=sum[l];
                    L[now]=L[l];fa[l]=now;
                    del(l);
                }else{
                    sum[now]+=sum[r];
                    R[now]=R[r];fa[r]=now;
                    del(r);
                }
            }else if(tmp>=0){
                ans=ans+(tmp+1)*(tmp+1)*sz+2*(tmp+1)*sum[now];
                sum[now]+=(tmp+1)*sz;
                val[now]+=tmp+1;
            }
        }
        LL la=val[ufs(nxt[0])];
        for(int k=ufs(nxt[ufs(nxt[0])]);k&&k!=cnt+1;k=ufs(nxt[k])){
            ans=ans+abs(val[k]-la)*c;
            la=val[k];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    第三题的失误好大的QAQ

    主要是没有发现只能增加的性质,也就是这个性质决定了贪心的正确性

    但是现在想想,就是考场上我想出贪心也不敢去写

    贪心功力太差,正确性的证明能力决定了自己的信心

    看来以后要学一学数学了 QAQ 顺便做做贪心题?

  • 相关阅读:
    写在毕业季前
    使用Github Page鼓励自己每日编程
    win8/Metro开发系列一 Xaml布局
    AlertDialog详解
    安卓项目文件目录
    Andriod布局之LinearLayout
    Andriod定时任务
    android 设置布局横屏竖屏
    Android默认启动程序问题
    Android全屏显示
  • 原文地址:https://www.cnblogs.com/joyouth/p/5552073.html
Copyright © 2011-2022 走看看