1. 程式人生 > >1821 最優集合

1821 最優集合

一個集合S的優美值定義為:最大的x,滿足對於任意i∈[1,x],都存在一個S的子集S’,使得S’中元素之和為i。
給定n個集合,對於每一次詢問,指定一個集合S1和一個集合S2,以及一個數k,要求選擇一個S2的子集S3(|S3|<=k),使得S1∪S3的優美值最大。
(集合元素可以重複)
Input

第一行一個數n,(n<=1000)
接下來n行,每行描述一個集合:
第一個數m,表示集合大小,接下來m個數,表示集合中的元素(m<=1000,元素<=10^9)
第n+2行一個數T,表示詢問次數(T<=10000)
接下來T行,每行3個數a,b,k,表示指定第a個集合為S1,第b個集合為S2,k的意義如題(a<=n,b<=n,k<=100,000)

Output

T行,每行一個數,表示對應詢問所能達到的最大優美值

Input示例

2
6 1 2 3 8 15 32
6 1 1 1 1 1 1
1
1 2 3

Output示例

64

/* 
    最優美值 為 s[j] + 1 < a[j+1] 的 s[j]
    如何從 集合b 中選出  一個  滿足 x <= s[j]  +1  的最大值 
    對 b 進行排序 , 把滿足  x<= s[j] 的值都放入stack中 。, stack.top() 就是   最大的 x; 
     對於  k 次 以上操作, 首先完成一次,更新 最優美值 。 
*/
#include <iostream> #include <algorithm> #include <stack> #include <cstdio> using namespace std; int se[1005][1005]; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return
x*f; } int main(){ int n,m,k,t,a,b,num; n = read(); for(int i=1;i<=n;i++){ se[i][0] = read(); for(int j=1;j<=se[i][0];j++) se[i][j] = read(); sort(*(se+i)+1,*(se+i)+se[i][0]+1) ; se[i][se[i][0]+1] = 0 ; } t = read(); for(int i=0;i<t;i++){ a = read(), b = read(), k = read(); int size = se[a][0], z = 1; long long btf = 0; stack<int> sta; for(int j=1;j<=size;j++){ if(btf + 1 >= se[a][j]) { btf = btf + se[a][j]; continue; } else{ while(btf+1 < se[a][j] && k){ for(;btf+1 >= se[b][z] && z <= se[b][0];z++){ sta.push(se[b][z]); } if(!sta.empty()){ btf += sta.top(); sta.pop(); } k--; } } if(btf + 1 >= se[a][j]) btf = btf + se[a][j]; else break; } while(k){ if(!sta.empty() ){ btf += sta.top(); sta.pop(); } k--; } printf("%lld\n",btf); } return 0; }