51NOD 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
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 1e3+10, maxn = 1e3+20, mod = 1e9+7, inf = 2e9; int a[N][N],n,T,b[N],H[N]; stack <int > q; void solve(int ii,int jj,int k) { LL ans = 0; int tmp1 = 1; while(!q.empty()) q.pop(); for(int i = 1; i <= a[ii][0]; ) { if(ans + 1 >= a[ii][i]) { ans += a[ii][i]; ++i; } else{ if(!k) break; if(q.empty()) break; while(!q.empty() && k) { ans += q.top(),q.pop(),k--; break; } } for(int j = tmp1; j <= a[jj][0]; ++j) { if(ans + 1 >= a[jj][j]) { q.push(a[jj][j]); tmp1 = j+1; } else break; } } while(!q.empty() && k) { ans += q.top(); q.pop(); k--; } printf("%lld\n",ans); } int main() { scanf("%d",&n); for(int i = 1; i <= n; ++i) { scanf("%d",&a[i][0]); for(int j = 1; j <= a[i][0]; ++j) { scanf("%d",&a[i][j]); } sort(a[i] + 1, a[i] + a[i][0] + 1); } scanf("%d",&T); while(T--) { int i,j,k; scanf("%d%d%d",&i,&j,&k); solve(i,j,k); } return 0; }