• 2019.9.17 csp-s模拟测试45 反思总结


    来了来了,垃圾二连。【指两次发博客】

    看了一下题就匆匆回去上课,在课上一边听课一边水oi,大概用1h40min的时间想完三道题。最后回到机房只剩下40min的时间敲代码,于是T1骗了70分就走了…

    这次蛮开心的,垃圾没有什么高要求,三道题我的想法都或多或少和正解沾边就非常愉快了。

    T1:kill

    (想这题的时候遭到了非人的噪音干扰……)

    倒是想到题解里区间连续的性质了,但因为老毛病——思路太乱没有体系,并且容易把题想难——退而求次选择了稳妥的方法。

    我的做法是列出怪物和人以及终点的关系式,O(n2)算出人打每个怪的最终代价,然后二分最晚时间,再跑一个二分图匹配。复杂度多一个log,最后只拿到70分。

    正解是发现人们打的怪物是一段连续的区间。个人试着还原了一下之前想到这一点时的思路过程,大约是从s的两边考虑。先看s的一边,这边的人最优解一定是打个人到终点之间的怪。每个人的代价至少包括出发点到s的这一段。然后打完所有到终点的途中的怪物以后,剩下的人要考虑打比出发点离s更远的怪,或者越过s打另一边的怪。但是不论怎样打,一定是个连续的区间,这样更优。s的另一边同理。

    既然是一段连续的区间,直接枚举左端点然后更新答案就好。复杂度O(n2)。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m;
    const long long inf=1e18;
    long long p[5010],q[5010],s,ans=inf;
    int main()
    {
        scanf("%d%d%lld",&n,&m,&s);
        for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
        for(int i=1;i<=m;i++)scanf("%lld",&q[i]);
        sort(q+1,q+m+1);
        sort(p+1,p+n+1);
        for(int i=1;i<=m-n+1;i++){
            int k=i;
            long long num=0;
            for(int j=1;j<=n;j++){
                if((p[j]>=q[k]&&q[k]>=s)||(p[j]<=q[k]&&q[k]<=s)){
                    if(num<abs(p[j]-s))num=abs(p[j]-s);
                }
                else if(num<abs(2*q[k]-(p[j]+s)))num=abs(2*q[k]-(p[j]+s));
                k++;
            }
            ans=min(num,ans);
        }
        printf("%lld",ans);
        return 0;
    }
    View Code

    T2:beauty

    自己的思路弯弯绕最后绕到了点分治去,中间倒是想到过对于每个节点,子树里能和外面连的就尽量向外连,其余自己匹配。一定是一条边被经过尽量多次更优。

    然后我就傻掉了…

    最后其实是个贪心。对于每个子树中的关键点,假设有x个,贡献就是min(2k-x,x),即最多能通过上面这条边连多少个匹配。这样是尽量让所有能贡献的关键点都贡献了1。

    至于证明…非常玄学,感觉的确没错,但是我也不太肯定。

    学长的话:考场上大胆猜想,不用求证

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,k,a,siz[100010];
    long long ans;
    int b[100010],ver[200010],Next[200010],head[100010],tot;
    void add(int x,int y){
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    void dfs(int x,int fa){
        siz[x]=b[x];
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            dfs(y,x);
            siz[x]+=siz[y];
        }
        ans+=min(siz[x],2*k-siz[x]);
    }
    int main()
    {
        scanf("%d%d%d",&n,&k,&a);
        for(int i=1,x;i<=2*k;i++){
            scanf("%d",&x);
            b[x]=1;
        }
        for(int i=1,x,y;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        dfs(1,0);
        printf("%lld",ans);
        return 0;
    }
    View Code

    T3:weight

    上课的时候手造了几组样例。很直观地能看出,对于求出的最小生成树,非树边能达到的最大值就是两个端点走出去的路径上的最大值-1。

    树边这块我是有点懵…一开始以为是走到的路径上用到的最大值-1。然后还想了要不要用tarjan跑所有scc出来然后分别处理balabala…

    正解中非树边的处理没有太大区别,但是树边的思路完全不一样。对于树边,要考虑每一条两个端点走出去的路径会经过这条树边的非树边,在它们的值里取个min再-1。因为如果大于这个min-1就可以选那条非树边而不是这条树边。

    接下来就可以用树剖解决这些路径上的min和max的问题,树剖的复杂度是O(nlog2n)。

    然而最大的坑点出现了…就在两三个小时以前刚刚得知,在节点1所在连通块以外的所有边的答案都要输出0。

    我:???

    于是加了个判断,快乐地过了…这就是我调了一中午的原因吗

    因为这个坑点,想了各种奇怪的做法。比如对于图中的桥边,最后的答案一定是-1,所以写了个tarjan求桥,也算复习了一下…

    最后发现第一版代码就可以过orz

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,a,cnt,ans[100010];
    const int inf=2147483647;
    int val[100010],lip[100010],ff[100010],dep[100010],rec[100010],rec1[100010];
    int f[100010],v[100010],siz[100010],son[100010];
    int ver[200010],Next[200010],head[100010],edge[200010],tot;
    void add(int x,int y,int z){
        ver[++tot]=y;
        Next[tot]=head[x];
        edge[tot]=z;
        head[x]=tot;
    }
    struct node{
        int x,y,z,id;
    }edg[100010];
    bool cmp(node a,node b){
        if(a.z<b.z)return true;
        else return false;
    }
    struct tree{
        int l,r,maxx,minn,tag;
    }b[400010];
    int get(int x){
        if(f[x]==x)return x;
        else return f[x]=get(f[x]);
    }
    void dfs(int x,int fa){
        siz[x]=1;
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==fa)continue;
            dep[y]=dep[x]+1;
            ff[y]=x;
            val[y]=edge[i];
            dfs(y,x);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]])son[x]=y;
        }
    }
    void dfs1(int x,int upp){
        lip[x]=upp;
        rec[x]=++cnt;
        rec1[cnt]=x;
        if(!son[x])return;
        dfs1(son[x],upp);
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(y==son[x]||y==ff[x])continue;
            dfs1(y,y);
        }
    }
    void build(int p,int l,int r){
        b[p].l=l,b[p].r=r;
        b[p].tag=b[p].minn=inf;
        if(l==r){
            b[p].maxx=val[rec1[l]];
            return;
        }
        int mid=(l+r)/2;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        b[p].maxx=max(b[p*2].maxx,b[p*2+1].maxx);
    }
    void update(int p){
        if(b[p].tag!=inf){
            b[p*2].tag=min(b[p*2].tag,b[p].tag);
            b[p*2].minn=min(b[p*2].minn,b[p].tag);
            b[p*2+1].tag=min(b[p*2+1].tag,b[p].tag);
            b[p*2+1].minn=min(b[p*2+1].minn,b[p].tag);
            b[p].tag=inf;
        }
    }
    void change(int p,int l,int r,int z){
        if(l<=b[p].l&&b[p].r<=r){
            b[p].minn=min(b[p].minn,z);
            b[p].tag=min(b[p].tag,z);
            return;
        }
        update(p);
        int mid=(b[p].l+b[p].r)/2;
        if(l<=mid)change(p*2,l,r,z);
        if(r>mid)change(p*2+1,l,r,z);
        b[p].minn=min(b[p*2].minn,b[p*2+1].minn);
    }
    void work(int x,int y,int z){
        while(lip[x]!=lip[y]){
            if(dep[lip[x]]<dep[lip[y]])swap(x,y);
            change(1,rec[lip[x]],rec[x],z);
            x=ff[lip[x]];
        }
        if(x==y)return;
        if(dep[x]>dep[y])swap(x,y);
        change(1,rec[x]+1,rec[y],z);
    }
    int ask1(int p,int l,int r){
        if(l<=b[p].l&&b[p].r<=r){
            return b[p].maxx;
        }
        update(p);
        int mid=(b[p].l+b[p].r)/2;
        int sum=0;
        if(l<=mid)sum=max(sum,ask1(p*2,l,r));
        if(r>mid)sum=max(sum,ask1(p*2+1,l,r));
        b[p].minn=min(b[p*2].minn,b[p*2+1].minn);
        return sum;
    }
    int ask2(int p,int l,int r){
        if(l<=b[p].l&&b[p].r<=r){
            return b[p].minn;
        }
        update(p);
        int mid=(b[p].l+b[p].r)/2;
        int sum=inf;
        if(l<=mid)sum=min(sum,ask2(p*2,l,r));
        if(r>mid)sum=min(sum,ask2(p*2+1,l,r));
        b[p].minn=min(b[p*2].minn,b[p*2+1].minn);
        return sum;
    }
    int query1(int x,int y){//max
        int sum=0;
        while(lip[x]!=lip[y]){
            if(dep[lip[x]]<dep[lip[y]])swap(x,y);
            sum=max(sum,ask1(1,rec[lip[x]],rec[x]));
            x=ff[lip[x]];
        }
        if(x==y)return sum;
        if(dep[x]>dep[y])swap(x,y);
        sum=max(sum,ask1(1,rec[x]+1,rec[y]));
        return sum;
    }
    int query2(int x,int y){//min
        int sum=inf;
        while(lip[x]!=lip[y]){
            if(dep[lip[x]]<dep[lip[y]])swap(x,y);
            sum=min(sum,ask2(1,rec[lip[x]],rec[x]));
            x=ff[lip[x]];
        }
        if(x==y)return sum==inf?0:sum;
        if(dep[x]>dep[y])swap(x,y);
        sum=min(sum,ask2(1,rec[x]+1,rec[y]));
        return sum==inf?0:sum;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&a);
        for(int i=1,x,y,z;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            edg[i].x=x,edg[i].y=y,edg[i].z=z,edg[i].id=i;
        }
        sort(edg+1,edg+m+1,cmp);
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++){
            int x1=get(edg[i].x),y1=get(edg[i].y);
            if(x1!=y1){
                f[x1]=y1;
                v[i]=1;
                add(edg[i].x,edg[i].y,edg[i].z);
                add(edg[i].y,edg[i].x,edg[i].z);
            }
        }
        dfs(1,0);
        dfs1(1,1);
        build(1,1,cnt);
        for(int i=1;i<=m;i++){
            if(!v[i]){//更新左右端点到lca路径上最小值 
                work(edg[i].x,edg[i].y,edg[i].z); 
            }
        }
        for(int i=1;i<=m;i++){
            if(!v[i]){//查两端点到lca路径上最大值,-1 
                ans[edg[i].id]=query1(edg[i].x,edg[i].y)-1;
            }
            else{//查两端点到lca路径上最小值,-1 
                ans[edg[i].id]=query2(edg[i].x,edg[i].y)-1;
            }
            if(get(edg[i].x)!=get(1))ans[edg[i].id]=0;
        }
        for(int i=1;i<=m;i++)printf("%d ",ans[i]);
        return 0;
    }
    View Code

    然后马上又要考试了【本来以为不考】,希望机房里各位rp++吧

  • 相关阅读:
    uniapp 小程序全屏的实现
    element select失效问题 , vue刷新的两种方式
    正则表达式
    vue+element ui中select组件选择失效问题原因与解决方法
    java removeAll和重写equals、hashcode引起的性能问题
    hive sql取差集
    hive获取日期对应的星期
    Hive分组后取组内排名方法row_number
    用Apache Spark和TensorFlow进行的深度学习
    git从已有分支拉新分支开发
  • 原文地址:https://www.cnblogs.com/chloris/p/11544247.html
Copyright © 2020-2023  润新知