特殊处理$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.若$x<n$且$y=2$且$x e 1$,则加入三元组$(S-(a_{x+1,1}-a_{x+1,2})+(a_{x,1}-a_{x,2}),x+1,2,y)$
显然这一做法的复杂度为$o(nlog n)$,下面来证明其正确性——
用$d_{i}$去描述一组方案,即表示选择$a_{i,d_{i}}$,其能力值之和即$sum_{i=1}^{n}a_{i,d_{i}}$
考虑一组方案$d_{i}$,我们对其执行下面两种变化:
1.若$d_{x}>1$,令$d_{x}$减小1
2.若$d_{x}=1$且$d_{x+1}=2$(其中$x<1$),交换$d_{x}$和$d_{x+1}$
不难证明,这样得到的方案一定不劣于$d_{i}$(根据排序即可得到)
由此,问题也可以看作证明每一个不在堆中且未被选择的方案(以下称为判定方案)$d_{i}$,都存在一个堆中的三元组$(S,x,y)$以及其所对应的方案$d'_{i}$,满足$forall 1le i<x,d'_{i}=d_{i}$且$d_{i}$可以变为$d'_{i}$
(关于三元组所对应的方案$d'_{i}$,可以通过$S$的变化感性理解,显然其满足$d'_{x}=y,forall x<ile n,d'_{i}=1$)
关于如何将$d_{i}$变为$d'_{i}$,由于上述特殊条件,显然有以下策略:
1.若$d_{x}>d'_{x}=y$,则先将$forall x<ile n,d_{i}$都通过1操作变为1,最后再将$d_{x}$减小为$d'_{x}$
2.若$d_{x}=d'_{x}=y$,若$forall x<kle n,d_{k}=d'_{k}$即已经完成,否则即$exists x<kle n,d_{k} e d'_{k}$($d_{k}>d'_{k}=1$)
取其中最小的$k$,对于$iin (k,n]$都直接将$d_{i}$通过1操作变为1,再将$d_{k}$变为2,由于$forall x<i<k,d_{i}=d'_{i}=1$,因此直接通过2操作不断交换$d_{k-1}$和$d_{k}$、$d_{k-2}$和$d_{k}$……直至$d_{x+1}=2$,再对$x+1$执行1操作即可
3.若$d_{x}<d'_{x}=y$,由于增加$d_{x}$只有2操作,且只能增加为2,因此必然$y=2$($d_{x}=1$)
更进一步的,若$forall x<kle n,d_{k}=d'_{k}=1$即无解,否则类似前面,将$d_{x+1}$变为2,再交换$d_{x}$和$d_{x+1}$即可
(上述策略并不唯一,但这样有助于下面的分析)
仍然回到最初的命题,即证明判定方案$d_{i}$都存在都存在一个堆中的三元组$(S,x,y)$以及其所对应的方案$d'_{i}$,满足$forall 1le i<x,d'_{i}=d_{i}$且$d_{i}$可以变为$d'_{i}$
归纳此命题成立,考虑当我们删除$(S,x,y)$后(设其对应的方案为$d'_{i}$),所有能变为$d'_{i}$的判定方案$d_{i}$(注意这里有$d e d'$,因为$d'$已经被选择),按照上述策略将其操作为$d'$,并撤销最后一次操作,将所有可能得到的方案(即撤销最后一次操作后)都加入,显然仍然满足此条件(每一个$d_{i}$都可以变化为撤销最后一次操作后所产生的方案)
考虑最后一次操作,实际上只有对$x$执行1操作、对$x+1$执行1操作以及交换$d_{x}$和$d_{x+1}$,因此得到的方案也只有3种,即前面的3种转移所得到的方案(显然方案也符合之前的定义)
另外,我们还需要说明方案不会重复——
显然只需要考虑两个不同的方案,分别选择了一种操作后变成了相同的方案,由于$y+1>2$显然不可能
(一个例外是$(1,1)$和$(1,2)$分别使用第2和3种转移都会产生$(2,1)$,限制$x=1$时不能选择第3种转移即可)
综上,即证明正确性
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 }