#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開銷代碼。
作出的改變是把生成的和數集合中,連續的和數表示成范圍,這樣處理數據的數量級就大減,并且當發現存在兩個不連續的范圍后,就能馬上得出答案。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
