2013編程之美複賽A :无尽的编号 數據結構+貪心

时间限制: 1000ms 内存限制: 256MB

描述

在一条公路上,将要依次建造N座建筑。在每个建筑建成之后,都会用一个01串来给它编号。整条公路从起点到终点,所有建筑的编号都严格按照字典序递增的顺序来排列,而每在一个新的地方建起一个建筑时,它的编号会按以下规则确定:

1) 编号要比前一个建筑(起点方向)的字典序大,比后一个建筑(终点方向)的字典序小

3) 编号一定以1结尾

2) 编号要尽可能短,满足该条件时,字典序尽可能小

最开始时,公路的起点和终点上各有一个建筑,编号分别是0和1。接下来依次给出N个坐标 a1, a2, ..., aN,依次表示下一个建筑将要建造的位置,最后要问,当所有建筑建成时,这些建筑的编号总长度是多少,其中又出现了多少个字符1。所有建筑都在公路起点和终点之间,并且没有两个建筑建在同一个位置。

输入

输入文件包含多组测试数据。

第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。

每组数据中第一行为一个整数 N,表示将要建造的建筑数量,第二行是用单个空格隔开的N个互不相同的整数 a1, a2, ..., aN,表示依次将要建造的建筑所在的坐标。

输出

对于每组测试数据,输出一行"Case #X: Y Z",其中X表示测试数据编号,Y表示所有建筑编号总长,Z表示所有编号中字符1的数量。所有建筑包括起点和终点的这两个建筑。所有数据按读入顺序从1开始编号。

数据范围

小数据:T ≤ 100, 0 < N ≤ 100, 0 ≤ ai ≤ 1000

大数据:T ≤ 10, 0 < N ≤ 50000, 0 ≤ ai ≤ 500000

样例输入
1
5
1 2 3 4 5
样例输出
Case #1: 22 16

分析:
  假設我們上一次插入之後當前位置的最近的左邊位置的串的長度為len1,串中1的個數為num1,最近的右邊的串長度為len2,串中1的個數為num2。我們不難發現,當前位置的1的個數最小為 num1+1,長度最小為 max(len1,len2)

  對此,我們可以通過用樹狀數組或者平衡樹、線段樹、SET之類的來維護一下就行了。

一組數據:

數據:
3
5
1 2 3 4 5
5
5 4 3 2 1
3
2 1 3


答案:
Case #1: 22 16
Case #2: 22 6
Case #3: 10 5

  

代碼如下:

/*

分析:
    假設我們上一次插入之後當前位置的最近的左邊位置的串的長度為len1,
    串中1的個數為num1,最近的右邊的串長度為len2,串中1的個數為num2。
    我們不難發現,當前位置的1的個數最小為 num1+1,長度最小為 max(len1,len2)

    對此,我們可以通過用樹狀數組或者平衡樹、線段樹、SET之類的來維護一下
    就行了。

*/
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define lx(x) (x<<1)
#define rx(x) (x<<1|1)
#define debug puts("here")
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define foreach(i,vec) for(unsigned i=0;i<vec.size();i++)
#define pb push_back
#define RD(n) scanf("%d",&n)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w)

/******** program ********************/

struct node{
    int id,val,len;
    node(){}
    node(int _x,int _v,int q):id(_x),val(_v),len(q){}
    friend bool operator < (node a,node b){
        return a.id>b.id;
    }
    void out(){
        cout<<id<<" "<<val<<" "<<len<<endl;
    }
};

set<node> s;

int main(){

#ifndef ONLINE_JUDGE
	freopen("sum.in","r",stdin);
	//freopen("sum.out","w",stdout);
#endif

    int ncase,n;
    RD(ncase);
    rep1(Ncase,ncase){
        printf("Case #%d: ",Ncase);
        int x;
        RD(n);

        set<node>::iterator it;
        s.clear();
        s.insert( node(-1,0,1) ); // 可以為0
        s.insert( node(10000000,0,1) ); // 可以為500000,這兩處比賽過程中我WA了n次 = =。

        ll ans = 0;
        ll r = 0;
        rep1(i,n){
            RD(x);

            it = s.lower_bound( node(x,0,0) );
            node pre = *it;
            * it --;
            node nex = *it;

            int one = pre.val+1;
            ans += one;
            int len = max(nex.len , pre.len)+1;
            r += len;
            s.insert( node(x,one,len) );
        }
        cout<<r+2<<" "<<ans+1<<endl;
    }

	return 0;
}

  

原文地址:https://www.cnblogs.com/yejinru/p/3032876.html