一个集合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
﹡ LH
(题目提供者)
Visual C++的运行时限为:1000 ms ,空间限制为:131072 KB
示例及语言说明请按这里
允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章
对于一个集合的优美值now而言,假如存在一个集合的优美值为x并且x<=now+1的话,
呢两个集合加起来的优美值一定是now+x,因此我们在找第一个集合优美值的同时,
在第二个集合中每次贪心的找最大不超过now+1的子集合加入到集合1中,但是每次从头找回很耗时,
我们可以采取一些优化策略,比如标记这个数之前没用过的最大的数,可以用并查集搞搞。
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<functional>
using namespace std;
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define maxn 1008
#define lowbit(x) (x&-x)
#define eps 1e-9
ll a[maxn][maxn],parent[maxn];
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 find(int x)
{
if(parent[x]==x)
return x;
return parent[x]=find(parent[x]);
}
void solve(int p,int q,int k)
{
int i=1,j=1,x,now=0;
while(1)
{
if(i<=a[p][0] && a[p][i]<=now+1)
now+=a[p][i],i++;
else
{
if(k<=0)
break;
k--;
while(j<=a[q][0] && a[q][j]<=now+1)
j++;
j--;x=find(j);
if(x==0)
break;
now+=a[q][x];
parent[x]=find(x-1);
if(x==j)
j++;
}
}
printf("%d\n",now);
}
int main(void)
{
int n,k,i,j,x,y,T;
n=read();
for(i=1;i<=n;i++)
{
a[i][0]=read();
for(j=1;j<=a[i][0];j++)
a[i][j]=read();
sort(a[i]+1,a[i]+a[i][0]+1);
}
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&x,&y,&k);
for(i=0;i<=1002;i++)
parent[i]=i;
solve(x,y,k);
}
return 0;
}