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