zoukankan      html  css  js  c++  java
  • Highest Tower 18中南多校第一场H题

    一、题意

    给出N个方块,要求给出一个方案,使得
    1、 所有方块都被使用到(题目数据保证这点)

    2、所有方块垒成一个塔,且上面的方块宽度小于下面的方块

    3、每个方块只能用一次,可以横着或者竖着。

    n范围50w

    二、题解

      首先考虑表示一个正方形的方法:长度和宽度组成的无向图。

      因为必然要把所有方块都堆好,所以仅考虑冲突情况:即一个边长出现了多次(如果仅仅出现了一次就无须考虑,直接无缝的塞进适应的位置即可)。

      因而仅仅需要考虑连成片的图(联通块情况)。对于任意可行解,都有同一长度作为宽度不出现超过1次。

      对于一个图,都会有如下设定:

        1、每条边最多只能做一次“宽”,因而如果出现了多条边指向这个点的话,将会必然增加deg-1次高(因为每个边长作为宽度最多只能出现一次)

        2、对于树状情况,若果有X个长宽组成一个联通块,则必然至少包括X-1个边,讨论上条定理,必然会有一个边应当作为高出现,因而建议选择最大的。

    重新梳理下思路:

      1、考虑不同联通块,由于不存在相同的宽度,因此可以仅单独讨论其对答案的贡献(因为互相穿插互不影响)

      2、对于同一个联通块,应当认为仅仅存在两种情况——即树或者树多一条边:
          考虑每个点都是一个边长,每条边都是一个矩形,

            若有树则是,n个不同的点对应n-1个矩形,则认为有n-1个不同的长度分别担任“成为宽度”的重任;

            若有多一条边,则认为n个点对应n个矩形,则有正好n个不同的长度分别担任“成为宽度”的重任;

            在多一条边,则认为,n个不同的长度,要出n+1个矩形(考虑必然要有n+1个不同的长度担任“成为宽度”的重任,然额一共只有n,故不存在);

      3、对于每个点,如果被多次指向,那么必然应当“最少有size-1次担任“成为高度”的任务“,换句话说,最多成为一次宽度。因此,对于任何一点,都必然为答案贡献(size-1)*val[now]. 

      4、对于每个树,我们可以自由选择”哪个点为起始节点,即不被指向(换句话说,指定任意节点为根)将其点权值贡献给答案“

      5、对于树+1条边,参见2,认为“没得选”

    最后注意下数据太大,要首先离散化一下。

    三、代码 

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<string.h>
    #include<queue>
    
    using namespace std;
    
    #define ll long long
    
    
    const ll MAXN=500233;
    map<int,int> mapp;
    ll n,val[MAXN],vis[MAXN];
    vector<int>G[MAXN];
    ll deg,maxx;
    ll ans;
    
    void dfs(int now)
    {
        if(vis[now])return;
        vis[now]=1;
        ans+=val[now]*(G[now].size()-1);
        maxx=max(maxx,val[now]);
        deg+=G[now].size()-2;
        for(int i=0;i<G[now].size();++i)
        {
            dfs(G[now][i]);
        }
        
    }
    
    int main()
    {
        while(cin>>n)
        {
            mapp.clear();
            int id=0;
            for(int i=1;i<=MAXN;++i)G[i].clear();
            for(int i=1;i<=n;++i)
            {
                int a,b,aa,bb;
                scanf("%d%d",&a,&b);
                if(mapp.count(a))aa=mapp[a];
                else aa=mapp[a]=id++;
                if(mapp.count(b))bb=mapp[b];
                else bb=mapp[b]=id++;
                val[aa]=a;
                val[bb]=b;
                G[aa].push_back(bb);
                G[bb].push_back(aa);
            }
            memset(vis,0,sizeof(vis));
            ans=0;
            for(int i=0;i<id;++i)
            {
                if(!vis[i])
                {
                    deg=0;
                    maxx=0;
                    dfs(i);
                    if(deg<0)ans+=maxx;
                }
                
            }
            cout<<ans<<endl;
        }
        
        
        return 0;
    }
  • 相关阅读:
    文件读写,尝试filestream和streamreader,streamwriter
    打印控件ScriptX,手动安装ScriptX插件说明 只兼容IE
    JS 循环获取Repeater 中Checkbox1被选中的值
    页面传值出现乱码问题 window.showModalDialog()
    无法打开物理文件 操作系统错误 5:拒绝访问 SQL Sever
    js 获取时间给时间控件赋值
    css 固定在窗口底端
    后台转换JSON格式。ToJson
    JS 匿名函数的使用2
    JS 匿名函数的使用1
  • 原文地址:https://www.cnblogs.com/rikka/p/8727907.html
Copyright © 2011-2022 走看看