2013編程之美複賽A :无尽的编号 數據結構+貪心
這次比賽太水了,怎麼可以把A題過了,然後把D題小數據過了就可以進決賽?!(很顯然,我的修行還不夠,沒能進。。。)
题目列表 > 无尽的编号
时间限制: 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; }