CF1342F Make It Ascending

题目大意

给定一个长度为 n n n的序列 a a a,每次可以选择两个位置 i , j ( i ≠ j ) i,j(i\not=j) i,j(i​=j),令 a j = a i + a j a_j=a_i+a_j aj​=ai​+aj​并将 a i a_i ai​从序列中删除
求将原序列变成严格单调上升序列的最少操作次数
n ≤ 15 n\le15 n≤15


题目相当于:求将序列 a a a划分成若干集合 S 1 , S 2 , ⋯ , S c S_1,S_2,\cdots,S_c S1​,S2​,⋯,Sc​,集合之间有序,满足 S i S_i Si​之和小于 S i + 1 S_{i+1} Si+1​之和(即单调递增),且存在一个单调上升序列 p p p满足 p i ∈ S i p_i \in S_i pi​∈Si​,即我们最终会将 S i S_i Si​所有其他元素累和到原序列位置为 p i p_i pi​的元素上 求最多划分出多少集合

朴素的想法是将所有限制全部装进 D P DP DP里面,即设 f i , j , k f_{i,j,k} fi,j,k​表示当前考虑了编号为 i i i的数集,最后一个划分出的集合对应的 p p p的最小值为 j j j,且总和为 k k k时,最多划分出多少集合

转移根据实际意义显然

这样复杂度太大了 因为我们把值域装了进去 考虑如何把值域去掉

由于若 k > k ′ k>k^{'} k>k′且 f i , j , k ≤ f i , j , k ′ f_{i,j,k} \le f_{i,j,k^{'}} fi,j,k​≤fi,j,k′​则前者显然无用

这说明对于相同的 f i , j , k f_{i,j,k} fi,j,k​,仅有最小的 k k k有用

根据这一性质,我们尝试忽略无用状态,交换 D P DP DP的某一维度和值域

这意味着,我们设 f i , j , k f_{i,j,k} fi,j,k​表示当处于上述意义下的 i , j i, j i,j以及集合个数为 k k k时,最后一个集合的和的最小值

转移即在 i i i这一维枚举子集,同时枚举 j , k j,k j,k

转移条件有三个:

  1. ∑ p ∈ S a p > f i , j , k \sum_{p \in S} a_p > f_{i,j,k} ∑p∈S​ap​>fi,j,k​
  2. ∃ p ∈ S s.t. p > j \exists p \in S \text{s.t.} p >j ∃p∈Ss.t.p>j 设 p m i n p_{min} pmin​为最小的这样的 p p p
  3. i ∩ S = ∅ i \cap S = \varnothing i∩S=∅

则 f i , j , k f_{i,j,k} fi,j,k​可以转移到 f i ∪ S , p m i n , k + 1 f_{i \cup S,p_{min},k+1} fi∪S,pmin​,k+1​,并令后者对 ∑ p ∈ S a p \sum_{p \in S}a_p ∑p∈S​ap​取 m i n min min

容易发现 时间复杂度为 O ( 3 n n 2 ) \mathcal{O} (3^n n^2) O(3nn2)

由于不合法状态较多 故 ✓ \checkmark ✓


#include <bits/stdc++.h>
using namespace std;const int N = 16;
struct dat {int msk, num, pos;} tr[1 << N][N][N];
int T, n, a[N], ban[N], s[1 << N], f[1 << N][N][N];
vector <pair <int, int>> ans;
int find(int x) {int rnk = 1;for(int i = 1; i < x; i++) if(!ban[i]) rnk++;return rnk;
}
void calc(int msk, int num, int pos) {if(!msk) return;dat t = tr[msk][num][pos];calc(t.msk, t.num, t.pos);for(int i = 0; i < n; i++)if(msk - t.msk >> i & 1 && i != pos - 1)ans.push_back({i + 1, pos});
}
void solve() {cin >> n, ans.clear();for(int i = 0; i < n; i++) cin >> a[i];for(int i = 0; i < 1 << n; i++)for(int j = 0; j <= n; j++)for(int k = 0; k <= n; k++)f[i][j][k] = 1e9;f[0][0][0] = 0;for(int i = 1; i < 1 << n; i++)for(int j = 0; j < n; j++)if(i >> j & 1)s[i] = s[i - (1 << j)] + a[j];for(int i = 0; i < 1 << n; i++)for(int j = 0; j < n; j++)for(int k = 0; k < n; k++)if(f[i][j][k] < 1e9) {int C = (1 << n) - 1 - i;for(int S = C; S; S = (S - 1) & C)if(s[S] > f[i][j][k] && S >> k) {int nk = __builtin_ctz(S >> k << k) + 1;if(s[S] >= f[i + S][j + 1][nk]) continue;f[i + S][j + 1][nk] = s[S];tr[i + S][j + 1][nk] = {i, j, k};}}for(int num = n; num; num--)for(int pos = 0; pos <= n; pos++)if(f[(1 << n) - 1][num][pos] != 1e9) {calc((1 << n) - 1, num, pos);cout << ans.size() << endl;memset(ban, 0, sizeof(ban));for(auto it : ans) {cout << find(it.first) << " " << find(it.second) << endl;ban[it.first] = 1;}return;}
}
int main() {cin >> T;while(T--) solve();return 0;
}

CF1342F Make It Ascending相关推荐

  1. 一二三系列之状压DP——Max Correct Set(一)Neko Rules the Catniverse (Large Version)(二)Make It Ascending(三)

    文章目录 一:CF1463F 二:CF1152F2 三:CF1342F 一:CF1463F Max Correct Set 有一个结论:以x+yx+yx+y为周期排列填充一定是不劣于最后的答案的 令p ...

  2. 我的收藏中的十大开源论坛

    有许多用PHP,ASP.NET和Perl编写的免费开源论坛系统(公告板,留言板). 以下是我最喜欢的免费开源论坛收藏集的列表. 我只列出了具有详细文档和良好社区支持的论坛. PS此列表不按任何特定顺序 ...

  3. 【CF1342F】 Make It Ascending

    题目 题目描述 You are given an array aa consisting of nn elements. You may apply several operations (possi ...

  4. pandas使用sort_values函数对dataframe的日期数据列进行排序(设置ascending参数进行正序或者倒序排序)

    pandas使用sort_values函数对dataframe的日期数据列进行排序(设置ascending参数进行正序或者倒序排序) 目录

  5. seaborn可视化条形图并按照升序排序条形图进行可视化:Sort Bars in Barplot in Ascending Order in Python

    seaborn可视化条形图并按照升序排序条形图进行可视化:Sort Bars in Barplot in Ascending Order in Python 目录

  6. C语言实现升序优先队列Ascending priority queue(附完整源码)

    实现升序优先队列Ascending priority queue node结构体 升序优先队列Ascending priority queue完整源码(定义,实现,main函数测试) node结构体 ...

  7. 输入学生成绩,并按升序排列 Ascending.java

    import java.util.Arrays; import java.util.Scanner; public class Ascending{ public static void main(S ...

  8. R语言使用order函数对dataframe数据进行排序、基于多个字段(变量)进行升序排序(ASCENDING)

    R语言使用order函数对dataframe数据进行排序.基于多个字段(变量)进行升序排序(ASCENDING) 目录

  9. pandas使用read_csv函数读取csv数据、sort_index函数基于多层行索引对数据排序(设置ascending参数列表指定不同层行索引的排序方向)

    pandas使用read_csv函数读取csv数据.index_col参数指定作为行索引的数据列索引列表形成复合(多层)行索引.sort_index函数基于多层行索引对数据排序(设置ascending ...

最新文章

  1. 关于加载Fashion MNIST数据集时可能会出现的问题
  2. 新口令范筹(Token Scope)- viewables:read
  3. 【Paper】论文中定义、定理、引理、证明分别的含义
  4. 【中级软考】白盒测试和黑盒测试
  5. python实现文件上传和下载_[Python] socket实现TFTP上传和下载
  6. Samba安装配置用于虚拟机共享文件_很详细
  7. Zookeeper 安装和配置---学习一
  8. java super是什么意思_java中Super到底是什么意思?必须举例说明!
  9. GridView控件RowDataBound事件中获取列字段值的几种途径
  10. 惠普第八代游戏家族产品重磅首发,搭载英特尔第十二代酷睿处理器
  11. trunk配置功能详解
  12. 浙大 PAT b1036
  13. [转载] Flask+Celery+Redis简单操作
  14. 网站结构优化的基本方法
  15. Linux进程控制与进程优先级
  16. Unity--使用反编译软件ILSpy查看dll中的代码
  17. mqtt测试工具(持续更新...)
  18. 从零开始的数模学习(7):插值方法(预测类模型)
  19. 基于元数据规则的大数据解决方案
  20. python窗口截图快捷键_python 自定义截图快捷键

热门文章

  1. android 非常好用的日期时间api Jota-Time(获取具体年、月、日、时、分、秒)
  2. SSM+mysql机票订购系统-计算机毕业设计源码07780
  3. Java高性能高并发实战之页面优化技术(五)
  4. MAC系统如何更换管理员用户
  5. 紫微圣人的程序员人生第4回 [原创IT小说]-撒粉必用无人机,保命全靠路由器
  6. Latex排版Algorithm之algorithmic,algorithmicx,algorithm2e
  7. 摄影基础知识——ISO
  8. Kubernetes存储之Rook的ceph搭建
  9. FL Studio步进音序器中的节奏怎么制作
  10. 地震预测与概率(转)