【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?' ':' '); wt(x.val),ps(!m?' ':' '); 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; }