[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.若$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)$,下面来证明其正确性——
用$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 1\le i<x,d'_{i}=d_{i}$且$d_{i}$可以变为$d'_{i}$
(关于三元组所对应的方案$d'_{i}$,可以通过$S$的变化感性理解,显然其满足$d'_{x}=y,\forall x<i\le n,d'_{i}=1$)
关于如何将$d_{i}$变为$d'_{i}$,由于上述特殊条件,显然有以下策略:
1.若$d_{x}>d'_{x}=y$,则先将$\forall x<i\le n,d_{i}$都通过1操作变为1,最后再将$d_{x}$减小为$d'_{x}$
2.若$d_{x}=d'_{x}=y$,若$\forall x<k\le n,d_{k}=d'_{k}$即已经完成,否则即$\exists x<k\le n,d_{k}\ne d'_{k}$($d_{k}>d'_{k}=1$)
取其中最小的$k$,对于$i\in (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<k\le n,d_{k}=d'_{k}=1$即无解,否则类似前面,将$d_{x+1}$变为2,再交换$d_{x}$和$d_{x+1}$即可
(上述策略并不唯一,但这样有助于下面的分析)
仍然回到最初的命题,即证明判定方案$d_{i}$都存在都存在一个堆中的三元组$(S,x,y)$以及其所对应的方案$d'_{i}$,满足$\forall 1\le i<x,d'_{i}=d_{i}$且$d_{i}$可以变为$d'_{i}$
归纳此命题成立,考虑当我们删除$(S,x,y)$后(设其对应的方案为$d'_{i}$),所有能变为$d'_{i}$的判定方案$d_{i}$(注意这里有$d\ne 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 }
[loj6254]最优卡组的更多相关文章
- 【LOJ6254】最优卡组 堆(模拟搜索)
[LOJ6254]最优卡组 题面 题解:常用的用堆模拟搜索套路(当然也可以二分).先将每个卡包里的卡从大到小排序,然后将所有卡包按(最大值-次大值)从小到大排序,并提前处理掉只有一张卡的卡包. 我们将 ...
- HearthBuddy卡组
偶数萨 手打两天已上传说,各位加油 欧洲牧羊人 ### 火元素换艾雅# 职业:萨满祭司# 模式:狂野模式## 2x (2) 图腾魔像 # 2x (2) 大漩涡传送门 # 2x (2 ...
- 服务器&阵列卡&组raid 5
清除raid信息后,机器将会读不到系统, 后面若进一步操作处理, raid信息有可能会被初始化掉,那么硬盘数据就有可能会被清空, 导致数据丢失, 否则如果只是清除raid信息,重做raid是可以还原系 ...
- bzoj3574[Hnoi2014]抄卡组
http://www.lydsy.com/JudgeOnline/problem.php?id=3574 我们发现如果所有的字符串都有*,那么只需要比较他们的“前缀”和“后缀”相同即可.“前缀”指第一 ...
- luogu P3234 [HNOI2014]抄卡组
传送门 nmdwsm 自己看吧,不想写了qwq 垃圾代码如下 和题解完全不一样 #define LL long long #define uLL unsigned long long #define ...
- 洛谷P3234 抄卡组 [HNOI2014] 字符串hash
正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...
- 【HNOI2014】抄卡组
题面 题解 如果所有的字符串都有通配符,那么只要比较不含通配符的前缀和后缀就可以了. 否则一定有一个串没有通配符.找出这个字符串,然后将所有串与这个串匹配,通配符将\(B\)分成一段一段在\(A\)上 ...
- 【LG3234】[HNOI2014]抄卡组
题面 题解 分三种情况: 若所有串都没有通配符,直接哈希比较即可. 若所有串都有通配符, 把无通配符的前缀 和 无通配符的后缀哈希后比较即可. 中间部分由于通配符的存在,一定可以使所有串匹配. 若部分 ...
- BZOJ3574 HNOI2014抄卡组(哈希)
容易发现通配符中间的部分可以任意匹配,会造成的无法匹配的仅仅是前后缀,前缀和后缀可以分别独立处理.如果字符串均有通配符,只需要按前/后缀长度排序然后暴力匹配就可以了. 问题在于存在无通配符的字符串.显 ...
随机推荐
- Java到底怎么学?
你现在是不是想学Java,但很迷茫不知该从何下手,那么请认真看完这篇文章,希望对你有所帮助! 作为零基础刚刚接触Java的朋友们来说,我的建议还是先看视频,虽然有很多人说看视频学习慢,建议直接买优秀的 ...
- MySQL的详细讲解
目录 Mysql的架构与历史 MySQL的逻辑架构 更新中---- Mysql的架构与历史 MySQL的逻辑架构 第二层的架构是所有的跨引擎的功能实现的地方,例如:存储,触发器,视图等. 第三层半酣了 ...
- 题解 [HAOI2018]反色游戏
题目传送门 题目大意 给出一个 \(n\) 个点 \(m\) 条无向边的图,每个点都有一个 \(\in [0,1]\) 的权值,每次可以选择一条边,然后将该边相连两点权值异或上 \(1\).问有多少种 ...
- 洛谷3348 大森林 (LCT + 虚点 + 树上差分)
这可真是道神仙题QWQ问了好多\(dalao\)才稍微明白了一丢丢做法 首先,我们假设不存在\(1\)操作,那么对于询问的一段区间中的所有的树,他们的形态应该是一样的 甚至可以直接理解为\(0\)操作 ...
- 剑指offer:JZ8 二叉树的下一个结点
JZ8 二叉树的下一个结点 描述 给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针.下图为一棵有9个节点的二叉 ...
- java监控JVM的内存使用情况等
以下的程序监控参数的代码,有些是从网络上获取的,此处进行一个记录是为了以后如果要用到方便记录. 1.引入jar包,为了获取一些cpu的使用率等信息 <dependency> <gro ...
- 检查是否是BST 牛客网 程序员面试金典 C++ java Python
检查是否是BST 牛客网 程序员面试金典 C++ java Python 题目描述 请实现一个函数,检查一棵二叉树是否为二叉查找树. 给定树的根结点指针TreeNode* root,请返回一个boo ...
- C/C++如何传递二维数组?
用二维数组作为参数传递(用二维数组处理矩阵),但是希望接受传递二维数组参数的函数可以处理任意维度的数组(希望矩阵的行数和列数都是不固定的). ----------------------------- ...
- cf16E Fish(状压DP)
题意: N只FISH.每个回合会有一只FISH吃掉另一个FISH.直到池塘里只剩一只FISH. 给出aij:第i只FISH吃掉第J只FISH的概率. 问每一只FISH是最后存活者的概率. Input ...
- 『学了就忘』Linux基础命令 — 20、文件操作的相关命令
目录 1.touch 命令 2.stat命令 3.cat命令 4.more命令 5.less命令 6.head命令 7.tail命令 1.touch 命令 touch命令用于创建空文件或修改文件时间, ...