这是一场比较难的div2 ... 比赛的时候只出了AB
A很有意思 给出n个数 要求随意的把相邻的数合并成任意多数 最后没有为0的数 输出合并区间个数与区间
可以想到0可以合到任何数上并不改变该数的性质 所以如果不全是0 最后一定是有答案的 把所有的0都合并到最近的非0数上去 非0数不变
#include #include #include #include #include
B很无聊..下三子棋 现在该我们下x了 能否一步胜利或者不走就胜利了呢?
写一个很手动的check函数 先判断能否直接胜利 再枚举每一个可以放的位置 放下再check
#include #include #include #include #include
C一个比较耗费时间的字符串模拟 给出一些人的名字和他们说的话 有些话的发言人用?代替 要求 相邻的两句话不会是同一个人说的 一个人说的话不会提到自己的名字
先做一个字符串模拟 用map把人名编号 再用r[]记录每句话的发言人 用cx[][]来记录每句话中出现的人名 用ans[]来处理最后的答案
最后我们 会得到一个cx数组 记录每句没有主人的话能选择的人
会发现贪心好像是不可做的 当前这句话 如果我们做出一些选择 可能会影响到下一个人的选择
搜索的话 如果100句话都是?也会超时
可以利用cx[][]数组和r[]数组 做一个dp题
如果想不到怎么dp 可以去代码中寻找注释~
#include #include #include #include #include
D给出n个区间 要求必须选择k个区间 使这k个区间的交集最大
k个区间的交集形成的区间 它的l是这几个区间中的最大的l 而r是这几个区间中的最小的r
应当选择k个区间 使它们有最小的l和最大的r 所以动态的去想 我们可以将l从小往大选 并选择最大化的r 维护一个ans
先进行排序 使l尽可能的小 在其基础上r尽可能的小 这样 我们从1-n枚举区间 就可以直接得到最大的l了
因为我们选择的l 是逐渐增大的 所以为了保存足够大的r 需要一个优先队列来做 维护一个 < 的优先队列 存放每个区间的r
1-n枚举区间的过程 每次我们选择一个区间 向优先队列中压入它的r 如果当前队列的size < k 说明未达到题目要求 暂且不管
如果size > k 我们就q.pop 弹出当前最小的r 由于我们是动态维护了ans 所以 如果弹出最小的r 使我们失去了一个l
1 如果这个l 是当前区间最大的l 那么当前结果已经保留进了ans
2 如果这个l 不是当前区间最大的l 那么这个区间的移除会使ans增大
如果size == k 这个状态可能是size < k 或者 size > k 来的 如果是前者 我们就需要开始更新ans(事实上这一幕只会在第k个数字出现)
如果是后者 我们就需要分析 这个新区间 会不会已经被弹出去了?
1 弹出去了 那么现在其实没变化 不需要做什么改变
2 没弹出去 那么现在就需要更新一下答案 我们可以肯定 当前的交集区间的l 一定是新区间的l(sort的结果) 而r 就是优先队列的top 所以 res = q.top - 新区间.l + 1
判断是否弹出 需要判断新区间的r与top的关系
有一个问题是 新区间的r 可能已经被弹出去了 当前区间并没有加进去 但是因为优先队列有r=新区间.r 所以被误判
其实是不会造成影响的 因为对于这种情况 一定会有过去的res >= 现在的res
所以这样模拟完最后就可以得出ans了
题目要求输出一下区间的选择
如果ans是0 随便输出k个数就可以了
如果不是的话 由于我们不确定当前解是不是最优解 所以 过程中我们无法更新区间数的ans
但是我们可以在优先队列中 伴随r加上一个id 然后再跑一遍枚举 当res == ans的时候 队列里的id就是答案啦
聪明的你一定看到这里就完全理解了吧
#include #include #include #include #include