• 51Nod


    一个集合S的优美值定义为:最大的x,满足对于任意i∈1,x1,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)OutputT行,每行一个数,表示对应询问所能达到的最大优美值Sample Input

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

    Sample Output

    64

    题意:给出N个数列。Q次询问,每次询问形如(a,b,k),表示选定第a个数列,然后在b数列里选择k个数,使得ans最大,满足1到ans都可以被表示为这些选择的数的和的形式。

    思路:先看子问题:给定一个数列,如何求最大的ans; 假设已经选出一些数,ans=[1,x],如现在给出一个数t<=x+1,那么ans=[1,x+t],负责ans不变。

    所以现在即是排序,求出每个集合是ans,然后考虑在b数列选择最大的数t<=ans+1,更新ans=ans+t;同时,a数列的数可以随便选。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    int a[maxn][maxn],ans[maxn],pos[maxn];
    void read(int &x){
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    } 
    int main()
    {
        int N,Q,x,y,k,i,j;
        read(N);
        for(i=1;i<=N;i++){
            read(a[i][0]);
            for(j=1;j<=a[i][0];j++)
              read(a[i][j]);    
        }
        for(i=1;i<=N;i++){
            sort(a[i]+1,a[i]+a[i][0]+1);
            for(j=1;j<=a[i][0];j++){
                if(a[i][j]<=ans[i]+1) pos[i]=j, ans[i]+=a[i][j];
                else break;
            }
        }
        scanf("%d",&Q);
        while(Q--){
            read(x); read(y); read(k);
            int res=ans[x];
            priority_queue<int>q;
            int np=upper_bound(a[y]+1,a[y]+a[y][0]+1,res+1)-a[y],tk=k;
            for(i=np-1;i>=1&&tk;i--){
                q.push(a[y][i]); tk--;
            } //先挑大的选,这样k后面几个就可以不加进来。 是个小小的优化。 
            i=np;
            int tp=pos[x];
            while(k--&&!q.empty()){
                res+=q.top();q.pop();
                while(tp+1<=a[x][0]&&a[x][tp+1]<=res+1) tp++,res+=a[x][tp];
                for(;i<=a[y][0];i++)
                if(a[y][i]<=res+1) q.push(a[y][i]);
                else break;
            }
            printf("%d
    ",res);
        }
        return 0;
    } 
  • 相关阅读:
    C#及时释放代码
    软件本质是什么?
    WCF学习
    android 更新ui
    ijkplayer视频播放
    androidstudio集成ijkplayer教程
    IJKPlayer问题集锦之不定时更新
    github上十二款最著名的Android播放器开源项目
    让ubuntu支持GBK编码AAAAA
    adb命令--之查看进程及Kill进程
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9125779.html
Copyright © 2020-2023  润新知