zoukankan      html  css  js  c++  java
  • 7.4集训模拟赛7(白丢了100分的一天,WTF)

     A. 侦查(tarjan缩点)

    题目描述

    输入格式

    输出格式

    样例

    样例输入

    12 11
    10 11 2 3 4 5 1 1 1 1 1 1
    1 2
    2 3
    1 3
    4 5
    5 6
    6 7
    8 9
    9 12
    11 12
    10 11
    8 10 

    样例输出

    8 9 10 11 12
    1 2 3

     分析

    我恨死这道题了,(so  easy,but......),一个break写道括号外面了,结果第二问没有输出,~~~~~~~,

    这就是个简单tarjan缩点,然后记录SCC中的基地数和敌人数然后取max,在遍历一边每个点找出输出就ok,break,不要写错位置啊啊啊啊啊啊啊啊!!!

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1100;
    int n,m;
    int a[N];
    int sum[N],summ[N],dfn[N],low[N];
    int Time,tot,cnt,top;
    int x,y,g[N],head[N];
    bool vis[N];
    int sta[N];
    
    struct edge{
        int to;
        int ne;
    }e[N<<2];
    
    void add(int u,int v){
        e[++cnt].to = v;
        //e[cnt].w = w;
        e[cnt].ne = head[u];
        head[u] = cnt;
    }
    
    void tarjan(int u){
        dfn[u]=low[u]=++Time;
        vis[u]=1;sta[++top]=u;
        for(int i=head[u];i;i=e[i].ne){
            int v = e[i].to;
            if(!dfn[v]){
                tarjan(v);
                low[u] = min(low[u] , low[v]);
            }
            if(vis[v]){
                low[u] = min(low[u] , dfn[v]);
            }
        }
        if(dfn[u]==low[u]){
            tot++;
            //sum[tot]+=a[u];
            while(sta[top+1]!=u){
                int v = sta[top--];
                vis[v] = 0;
                sum[tot]+=a[v];
                summ[tot]++;
                g[v] = tot;
            }
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i])tarjan(i);
        }
        int jidi=-10,diren=-10;
        for(int i=1;i<=tot;i++){
            jidi = max(jidi,summ[i]);
            diren = max(diren,sum[i]);
        }
        //printf("%d  %d
    ",jidi,diren);
        for(int i=1;i<=n;i++){
            if(summ[g[i]]==jidi){
                for(int j=1;j<=n;j++){
                    if(g[j]==g[i]){
                        printf("%d ",j);
                    }
                }
                break;
            }
        }
        printf("
    ");
        for(int i=1;i<=n;i++){
            if(sum[g[i]]==diren){
                for(int j=1;j<=n;j++){
                    if(g[j]==g[i]){
                        printf("%d ",j);
                    }
                }
                break;//此处为窝的墓地
            }
        }
        return 0;
    }

    B. 借书(二分答案)

    题目描述

     输入格式

     输出格式

     样例

    样例输入

    6 3 
    5
    7
    1
    17
    13
    10

    样例输出

     7

    数据范围与提示

     分析

    就是道二分答案,其实这就是个题目模型,最小值最大化,最大值最小化(已经暗示是二分答案了),

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5+10;
    int n,m;
    int a[N];
    int maxn;
    int gd[N];//差分数组,记录差值
    int aa;
    int cnt;
    
    
    bool cheak(int x){
        aa=0,cnt=0;
        for(int i=1;i<n;i++){
            aa+=gd[i];
            if(aa>=x){//如果大于就加一,并把aa置为零
                cnt++;//方便下次在找
                aa=0;
            }
        }
        if(cnt+1>=m){//如果大于m,及能够选出m本书
            return true;//就true
        } else return false;//否则
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            maxn = max(maxn,a[i]);
        }
        sort(a+1,a+1+n);//排序
        for(int i=1;i<n;i++){
            gd[i] = a[i+1]-a[i];//差分数组
        }
        int l=0,r=maxn;
        while(l<=r){//二分
            if(r-l==1){//相差为一,就判断一下,否则就会死死死死循环
                if(cheak(r)){
                    l=r;
                }
                break;
            }
            int mid = (l+r)/2;
            if(cheak(mid)){
                l=mid;//如果能cheak,说明还有更大的向上更新
            } else {//不能就得向下更新
                r=mid;
            }
        }
        printf("%d",l);
    }

    C. 搜城探宝(树...树形dp?)

    题目描述

     输入格式

      输出格式

    样例

    样例输入

    8 4 
    1 2 
    1 3 
    2 4 
    2 5 
    3 6 
    3 7 
    6 8 
    2 5 1 4 6 1 1 10 

    样例输出

    27

    数据范围与提示

     分析

    额......这道题就是树形dp,不过要考虑传送门的问题,咋办昵!!!啧啧啧啧!!!!我们建一个虚点,就是n+1,因为情况不确定,所以可以枚举每一个点,让每一个点都做一次需点n+1的右子树,然后就dfs使劲搜。xiu,不过要注意一个点当完虚点后要归位。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 50;
    int ls[N],rs[N],fa[N];//左右儿子,以及父亲数组
    int n,key,a[N];
    int x,y,ans;
    
    int dfs(int x,int k){
        if(x==0)return 0;//叶子节点返回0
        if(k==1)return a[x];//只有一把钥匙开当前门
        int now = 0;
        for(int i=0;i<k;i++){//钥匙从一枚举,以为可能都用于开左子树,右子树
            now = max(dfs(ls[x],i)+dfs(rs[x],k-i-1)+a[x],now);
        }
        return now;
    }
    
    int main(){
        scanf("%d%d",&n,&key);
        for(int i=1;i<=n-1;i++){
            scanf("%d%d",&x,&y);
            if(!ls[x])ls[x] = y;//如果左儿子为空
            else rs[x] = y;//否则为右儿子
            fa[y]=x;//父亲
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        ls[n+1] = 1;//虚点左儿子为根节点
        for(int i=2;i<=n;i++){
            rs[n+1] = i;
            if(ls[fa[i]]==i){//若是左儿子
                ls[fa[i]]=0;
                ans = max(ans,dfs(n+1,key+2));
                ls[fa[i]] = i;//归位
            }
            else {//是右儿子
                rs[fa[i]] = 0;
                ans = max(ans,dfs(n+1,key+2));
                rs[fa[i]] = i;归位
            }
        }
        printf("%d
    ",ans);
        return 0;
    }

    D. MM不哭(dp)

    题目描述

     输入格式

     输出格式

     样例

    样例输入

    4
    3
    2 2
    5 8
    6 1
    8 7

    样例输出

    56

     分析

    看到这想到了......

    这和洛谷关路灯差不多,我们定义数组f[ i ][ j ][ 1(0) ]是处理完i到j最后停在i(0)或停到j(1)的最少消耗,那么

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1010;
    int n,v,x;
    int f[N][N][2];
    int sum[N];
    struct node{
        int x;
        int w;
    }e[N];
    
    bool cmp(node a,node b){//结构体排序
        return a.x<b.x;
    }
    
    int main(){
        scanf("%d%d",&n,&v);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&e[i].x,&e[i].w);
        }
        /*v = e[v].x;//这里加不加都一样
        //printf("%d",x);//因为题中的数据就是递增的
        sort(e+1,e+1+n,cmp);//虽然说没有说
        for(int i=1;i<=n;i++){//不要问我怎么知道的
            if(v==e[i].x){//问就是歪打正着
                v=i;
            }
        }*/
        for(int i=1;i<=n;i++){
            sum[i] = sum[i-1]+e[i].w;//前缀和
        }
        memset(f,0x3f,sizeof(f));//初始化最大值
        f[v][v][1]=f[v][v][0] = 0;//在v位置没动时消耗为0
        for(int l = 2;l <= n;l++){
            for(int i=1;i+l-1<=n;i++){
                int j = i+l-1;
                if(i < x-l+1)continue;//i不能在范围之外
                //if(j>n)break;
                int n1=sum[i]+sum[n]-sum[j];
                int n2=sum[i]+sum[n]-sum[j];
                int n3=sum[i-1]+sum[n]-sum[j-1];
                int n4=sum[i-1]+sum[n]-sum[j-1];
                f[i][j][0] = min(f[i+1][j][0]+n1*(e[i+1].x-e[i].x),f[i+1][j][1]+n2*(e[j].x-e[i].x));//两个(额,或者说四个)状态
                f[i][j][1] = min(f[i][j-1][0]+n3*(e[j].x-e[i].x),f[i][j-1][1]+n4*(e[j].x-e[j-1].x));
            }
        }
        printf("%d
    ",min(f[1][n][0],f[1][n][1]));//取两种情况的最小值
        return 0;
    }

     恭喜你找到一只正在洗澡的pig,稍等一会,分析马上来

    由于这是记录日常博客,可能题分析的不是太多(主要是时间不够),那就贴上教练博客

    也算偏偏访量吧

  • 相关阅读:
    面试总结
    回溯-递归练习题集
    2018年度业余学习总结
    12306余票高效查询--clojure实现
    Mac中wireshark如何抓取HTTPS流量?
    2017年学习总结
    Clojure——学习迷宫生成
    新生帝之2016年的计划,努力去做好!
    EmitMapper
    ASP.NET 修改地址返回图片缩率图
  • 原文地址:https://www.cnblogs.com/LightyaChoo/p/13235801.html
Copyright © 2011-2022 走看看