Timus 1515

#include <iostream>
using namespace std;

#define MAX 10000

int origin[101] = {0};

typedef
struct range_st {
int l,r;
} range_st,
*range_t;

int ranges_len = 0;
range_st ranges[MAX];
range_st temp[MAX];

void union_range(range_st rg) {
int i,j,union_count;
for(i=0;i<ranges_len && ranges[i].r + 1 < rg.l;i++) ; //find the first range that can union rg
if(i == ranges_len) //no such range found
ranges[ranges_len++] = rg;
else if(ranges[i].r < rg.r) {
ranges[i].r
= rg.r;
}

union_count
= 0;
for(j=i+1;j<ranges_len;j++) {
if(ranges[i].r + 1 >= ranges[j].l) { //self-union occur
if(ranges[i].r < ranges[j].r)
ranges[i].r
= ranges[j].r;

union_count
++;
}
}

ranges_len
-= union_count;
}

void update_range(int n) {
int temp_len = 0;
range_st rg;
for(int i=0;i<ranges_len;i++) {
rg.l
= ranges[i].l + n;
rg.r
= ranges[i].r + n;
temp[temp_len
++] = rg;
}

for(int i=0;i<temp_len;i++)
union_range(temp[i]);
}

void print_range() {
for(int i=0;i<ranges_len;i++)
printf(
"(%d,%d) ", ranges[i].l, ranges[i].r);
printf(
"\n");
}

int main() {

int i,j,k;
int m,n,d,t,ret;
range_st rg;
int N;
cin
>>N;
for(i=0;i<N;i++)
cin
>>origin[i];

rg.l
= rg.r = 0;
ranges[ranges_len
++] = rg; //init range (0,0)

for(i=0;i<N;i++) {
n
= origin[i];

update_range(n);

//print_range();

if(ranges_len > 1)
break;
}

ret
= ranges[0].r + 1;

cout
<<ret<<endl;

return 0;
}

囧死的一题目,给出N个数(N<=100),求一个最小的数,这个数不能是这N个数的任何组合的求和数。

暴力的思维让我去计算所以组合数,根据前i个数生成的所有和数,去计算第i+1个数能够生成的和数,然后把这两堆和数做合并,这可以正确地求出所有可能的和数,但就死活ME,因为数量太大了。注意给出的N个数,每个数最大值是10^6。

在使用第i个数的时候,其实就可以从集合中遍历,查看是否存在一个数少于Ni并且不在集合中,如果是,那么这个就是答案,但写的代码过不了,一直WA 3。

后来换了个思维,通过在草稿上写了些例子,认为这题目应该有很高效的计算方法才是,结果就得出了最后AC的代码。属于0开销代码。

作出的改变是把生成的和数集合中,连续的和数表示成范围,这样处理数据的数量级就大减,并且当发现存在两个不连续的范围后,就能马上得出答案。

posted @ 2011-08-05 14:15  DOF_KL  阅读(223)  评论(0编辑  收藏  举报