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;
}

 


    
posted @ 2017-03-27 16:21  meekyan  阅读(144)  评论(0编辑  收藏  举报