zoukankan      html  css  js  c++  java
  • CF796C Bank Hacking

    题目链接

    分析

    题目好长
    其实也不是很长,我感觉按照原题的说法去理解这个题会比较好理解一些。
    就是说,我先从树上找到一个点,然后一步一步的去覆盖这棵树,你只能覆盖点权比你小的点,问覆盖整棵树需要你的权值最小是多少。
    首先先考虑我会去从哪个点开始,显然是先覆盖点权大的,因为它迟早都要被覆盖,如果现在不去覆盖,那再覆盖它,它的点权就会增加,所以肯定要先覆盖点权大的,进而可以知道,一个点如果有可能成为最大值,它的点权最多只会被+2,因为我要去覆盖它,首先覆盖它的半相邻点,再去覆盖它的相邻点,
    如果它变大了,那我下一步就要把它覆盖掉,因此答案最多只可能是最大值+2。
    接下来就是一个分类讨论了,假设最大值为(max),我们只要找(max-1)的点就行了,因为(max-2)的点最多也只会被搞成(max),如果所有的(max-1)的点都连在(max)上,那我搞完(max)就能在他们增加1到(max-1+1)的时候,破坏掉他们,所以此时答案为(max),如果一个(max-1)的点也没有,那答案显然也是这个。

    如果他们不连在一起呢?

    那我覆盖(max)和6的时候,(max-1)都要+1,最后就成了(max+1),所以当没有连在一起的时候,就是(max+1)
    那么有不止一个(max)的时候呢?

    如果这些都连在一起,答案是(max+1),不管是连在(max)上还是别的上边,只要他们互为相邻点或半相邻点就好。

    那么跟上边推(max-1)的时候一样,只不过(max)最多变成(max+2)
    也就这几种情况了,模拟一下就出来??

    #include<cstdio>
    #include<limits>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=3e5+10;
    struct Edge{
        int to,nxt;
    }e[N<<1];
    int h[N],idx,w[N];
    void Ins(int a,int b){
        e[idx].to=b;e[idx].nxt=h[a];h[a]=idx++;
    }
    int main(){
        memset(h,-1,sizeof(h));
        int n,mx,cnt,cntsec,pos;
        mx=INT_MIN;cntsec=cnt=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&w[i]);
            if(w[i]>mx){
                mx=w[i];
                pos=i;
            }
        }
        for(int i=1;i<=n;i++){
            if(w[i]==mx)cnt++;
            if(w[i]==mx-1)cntsec++;
        }
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            Ins(a,b);
            Ins(b,a);
        }
        if(cnt==1){
            if(cntsec==0){
                printf("%d
    ",mx);
                return 0;
            }
            int nxt=0;
            for(int i=h[pos];~i;i=e[i].nxt){
                if(w[e[i].to]==mx-1)nxt++;
            }
            if(nxt==cntsec)
                printf("%d
    ",mx);
            else printf("%d
    ",mx+1);
            return 0;
        }
        if(cnt>1){
            for(int i=1;i<=n;i++){
                int nxt=0;
                for(int j=h[i];~j;j=e[j].nxt){
                    if(w[e[j].to]==mx)nxt++;
                }
                if((nxt==cnt&&w[i]!=mx)||(nxt==cnt-1&&w[i]==mx)){
                    printf("%d
    ",mx+1);
                    return 0;
                }
            }
        }   
        printf("%d
    ",mx+2);
        return 0;
    }
    
  • 相关阅读:
    CAST和CONVERT
    #pragma 预处理指令详解
    Android系统移植主要事项
    Java动态绑定机制的内幕
    Java接口和抽象类用法总结
    Android工程的编译过程
    点击按钮,并且实现增加一个按钮的效果 (附效果图)
    iOS-设置导航栏"返回"按钮 (附效果图)
    常用代码整理(重要)
    NSTimer 的暂停与恢复运行。
  • 原文地址:https://www.cnblogs.com/anyixing-fly/p/12806827.html
Copyright © 2011-2022 走看看