[loj6254]最优卡组

特殊处理$c_{i}=1$的$i$,显然对这些$a_{i,1}$求和即可,以下都假设$c_{i}\ge 2$

对于每一个$i$,将$a_{i,j}$从大到小排序;接下来,对于所有$i$,按照$a_{i,1}-a_{i,2}$从小到大排序

在堆中维护三元组$(S,x,y)$,按照$S$从大到小维护(即堆顶$S$最大),初始在堆中加入$(\sum_{i=1}^{n}a_{i,1},1,1)$

每一次取出堆顶的三元组$(S,x,y)$并输出$S$,接下来:

1.若$y<c_{x}$,则加入三元组$(S-(a_{x,y}-a_{x,y+1}),x,y+1)$

2.若$x<n$,则加入三元组$(S-(a_{x+1,1}-a_{x+1,2}),x+1,2,y)$

3.若$1<x<n$且$y=2$且$x\ne 1$,则加入三元组$(S-(a_{x+1,1}-a_{x+1,2})+(a_{x,1}-a_{x,2}),x+1,2,y)$

显然这恰能不重不漏的得到所有方案且权值和单调不降,即具有正确性

时间复杂度为$o(n\log n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define ll long long
 5 struct Data{
 6     int x,y;
 7     ll ans;
 8     bool operator < (const Data &k)const{
 9         if (ans!=k.ans)return ans>k.ans;
10         return make_pair(x,y)<make_pair(k.x,k.y);
11     }
12 };
13 multiset<Data>s;
14 vector<int>a[N];
15 int n,m,x,y,id[N];
16 ll sum;
17 bool cmp1(int x,int y){
18     return x>y;
19 }
20 bool cmp2(int x,int y){
21     return a[x][0]-a[x][1]<a[y][0]-a[y][1];
22 }
23 int main(){
24     scanf("%d%d",&n,&m);
25     for(int i=1;i<=n;i++){
26         scanf("%d",&x);
27         for(int j=1;j<=x;j++){
28             scanf("%d",&y);
29             a[i].push_back(y);
30         }
31         sort(a[i].begin(),a[i].end(),cmp1);
32         sum+=a[i][0];
33         if (x==1){
34             n--;
35             a[i--].clear();
36         }
37     }
38     for(int i=1;i<=n;i++)id[i]=i;
39     sort(id+1,id+n+1,cmp2);
40     s.insert(Data{1,0,sum});
41     for(int i=1;i<=m;i++){
42         Data o=(*s.begin());
43         s.erase(s.begin());
44         x=o.x,y=o.y,sum=o.ans;
45         printf("%lld ",sum);
46         if (y+1<a[id[x]].size())s.insert(Data{x,y+1,sum-(a[id[x]][y]-a[id[x]][y+1])});
47         if (x<n)s.insert(Data{x+1,1,sum-(a[id[x+1]][0]-a[id[x+1]][1])});
48         if ((x<n)&&(y==1)&&(x!=1))s.insert(Data{x+1,1,sum-(a[id[x+1]][0]-a[id[x+1]][1])+(a[id[x]][0]-a[id[x]][1])});
49     } 
50 } 
View Code

 

posted @ 2021-06-04 09:42  PYWBKTDA  阅读(135)  评论(0编辑  收藏  举报