【LOJ6254】最优卡组 堆(模拟搜索)

【LOJ6254】最优卡组

题面

题解:常用的用堆模拟搜索套路(当然也可以二分)。先将每个卡包里的卡从大到小排序,然后将所有卡包按(最大值-次大值)从小到大排序,并提前处理掉只有一张卡的卡包。

我们将状态用一个四元组(val,x,y,z)表示,意思是当前所有卡的和是val,我们人为的选择了前x包卡(后n-x包卡都选的是最大值),第x包卡选择了第y张,z表示当前状态是否是由2或3转移得来的,具体含义见下面(设计的非常巧妙,一开始自己想了几个策略都有遗漏)。

那么这个状态可以扩展到如下几种状态:

1.如果y<cx,则我们可以选择卡包x的下一张卡,即扩展到(val+...,x,y+1,0)
2.如果x<n(已经处理掉只有一张卡的卡包了),则我们可以选择下一割卡包的第二张卡,即拓展到(val+...,x+1,2,1)
3.如果x<n且z=1,我们可以撤销这割卡包的第二张卡,选择下一个卡包的第二张卡,即拓展到(val+...,x+1,2,1)

容易证明这样能不重不漏的,从大到小的枚举到所有状态。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=300010;
struct node
{
	ll val;
	int x,y;
	bool z;
	node() {}
	node(ll a,int b,int c,bool d) {val=a,x=b,y=c,z=d;}
	bool operator < (const node &a) const
	{
		return val<a.val;
	}
};
priority_queue<node> q;
int n,m;
int p[maxn],c[maxn];
vector<ll> v[maxn];
inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll rd()
{
	ll ret=0;	char gc=nc();
	while(!isdigit(gc))	gc=nc();
	while(isdigit(gc))	ret=ret*10+(gc^'0'),gc=nc();
	return ret;
}
char puf[100000],*p3=puf;
inline void ps(const char &x)
{
	if(p3==puf+100000)	fwrite(puf,1,100000,stdout),p3=puf;
	*p3++=x;
}
inline void flush()
{
	fwrite(puf,1,p3-puf,stdout);
}
inline void wt(ll x)
{
	static char sta[20];
	int top=0;
	if(!x)	ps('0');
	while(x)	sta[++top]=(x%10)^'0',x/=10;
	while(top)	ps(sta[top--]);
}
bool cmp1(const int &a,const int &b)
{
	return a>b;
}
bool cmp2(const int &a,const int &b)
{
	if(c[a]==1||c[b]==1)	return c[a]!=1;
	return v[a][0]-v[a][1]<v[b][0]-v[b][1];
}
int main()
{
	//freopen("loj6254.in","r",stdin);
	n=rd(),m=rd();
	int i,j,a,b;
	node x=node(0,1,0,0);
	for(i=1;i<=n;i++)
	{
		v[i].clear(),c[i]=rd(),p[i]=i;
		for(j=0;j<c[i];j++)	v[i].push_back(rd());
		sort(v[i].begin(),v[i].end(),cmp1);
		x.val+=v[i][0];
	}
	sort(p+1,p+n+1,cmp2);
	while(c[p[n]]==1)	n--;
	q.push(x);
	while(m--)
	{
		x=q.top(),q.pop(),a=x.x,b=x.y;
		//printf("%lld%c",x.val,!m?'\n':' ');
		wt(x.val),ps(!m?'\n':' ');
		if(b+1<c[p[a]])	q.push(node(x.val-v[p[a]][b]+v[p[a]][b+1],a,b+1,0));
		if(a<n)	q.push(node(x.val-v[p[a+1]][0]+v[p[a+1]][1],a+1,1,1));
		if(a<n&&x.z)	q.push(node(x.val-v[p[a]][1]+v[p[a]][0]-v[p[a+1]][0]+v[p[a+1]][1],a+1,1,1));
	}
	flush();
	return 0;
}

 

posted @ 2017-12-24 16:11  CQzhangyu  阅读(579)  评论(0编辑  收藏  举报