首页 > 其他分享 >[dp 记录] CF1342F

[dp 记录] CF1342F

时间:2023-02-09 13:34:54浏览次数:52  
标签:记录 int ++ CF1342F msk ans 集合 dp

trick:dp 数组定义域与值域的互换。

基本复读魏老师题解。

题意:

将 \(n\) 数合并为 \(m\) 集合,每个集合取出一个代表元,使得(代表元下标,集合和)构成偏序关系。最大化 \(m\) 并输出方案。

\(O(n^2 3^n)\)。那个数据范围很鬼畜。

朴素的 dp 需要记录已选元素、上一个集合的代表元、上个集合和。然后会发现和一维太大了。但是整个 dp 的值域仅有 \(n\) 大小。

注意到若 \(dp_{i,j,k} = dp_{i,j,k'}\) 且 \(k < k'\),则 \(k'\) 无用。因此只用对每个 \(t\) 记录使 \(dp_{i,j,k}=t\) 的最小 \(k\)。然后值域就忽然小到能做了。

这样子本质是贪心排除了一些不可能成为答案的集合。

转移时也可以贪心一些:枚举补集用当前状态更新下一个状态,则只用贡献给 最小大于上代表元的新集合内数字 处。仍是贪心显然。

代码有点长但思路很清晰。这题不错,但感觉知道 trick 后还是平常了。

#include <cstdio>
#include <tuple>
#include <vector>
using namespace std;
const int M = 16, inf = 1e9 + 7;
int f[1 << M][M][M]; // f[i][j][k] := 已选数集 i,最后一个集合代表元为 j,已有 k 集合,时的最小最后集合和
tuple<int, int, int> p[1 << M][M][M];
int a[M], s[1 << M];
vector<pair<int, int> > ans;
void solve() {
  int n; scanf("%d", &n);
  for(int i = 0; i < n; i++) scanf("%d", &a[i]);
  int all = (1 << n) - 1;
  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] = inf;
  f[0][0][0] = 0;
  for(int i = 0; i < 1 << n; i++) s[i] = 0;
  for(int i = 0; i < n; i++) s[1 << i] = a[i];
  for(int i = 0; i < n; i++)
    for(int j = 0; j < 1 << n; j++)
      if((j >> i) & 1) s[j] += s[j ^ (1 << i)];
  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] == inf) continue;
        int U = all ^ i;
        for(int T = U; T; T = (T-1) & U) {
          if(s[T] > f[i][j][k] && (T >> j)) {
            int t = __builtin_ctz(T >> j << j) + 1; // 此处 +1 平移
            if(f[i+T][t][k+1] > s[T]) {
              f[i+T][t][k+1] = s[T];
              p[i+T][t][k+1] = make_tuple(i, j, k);
            }
          }
        }
      }
  for(int t = n; t >= 1; t--) {
    for(int i = 1; i <= n; i++)
      if(f[all][i][t] != inf) {
        ans.clear();
        auto dfs = [&](auto self, tuple<int, int, int> t) -> void {
          int msk = get<0>(t), pl = get<1>(t), num = get<2>(t);
          if(!msk) return;
          self(self, p[msk][pl][num]);
          int x = msk - get<0>(p[msk][pl][num]);
          for(int i = 0; i < n; i++) {
            if(x & (1 << i) && i+1 != pl) ans.push_back(make_pair(i+1, pl));
          }
        } ;
        dfs(dfs, make_tuple(all, i, t));
        printf("%d\n", ans.size());
        vector<bool> del(n+1);
        auto find = [&](int x) -> int {
          int ans = 1;
          for(int i = 1; i < x; i++) ans += del[i] == 0;
          return ans;
        } ;
        for(int i = 0; i < ans.size(); i++)
          printf("%d %d\n", find(ans[i].first), find(ans[i].second)),
          del[ans[i].first] = 1;
        return;
      }
  }
}
int main() {
  int T; scanf("%d", &T);
  while(T--) {
    solve();
  }
}

标签:记录,int,++,CF1342F,msk,ans,集合,dp
From: https://www.cnblogs.com/purplevine/p/17104942.html

相关文章

  • Qt多线程编程之QThreadPool 和 QRunnable使用
     说到线程通常会想到QThread,但其实Qt中创建线程的方式有多种,这里主要介绍其中一种QRunnable,QRunnable和QThread用法有些不同,并且使用场景也有区别。要介绍QRunnable的用......
  • 自我介绍及学习记录
    |这个作业属于哪个课程|https://edu.cnblogs.com/campus/fzzcxy/2023learning/join?id=CfDJ8GXQNXLgcs5PrnWvMs4xAGN4cHWWqRMNY7CzDMC-49n8j6IT5cvnqlNnraGz8DcrOqn-fXMeSp......
  • 20230112_每日学习记录
    20230112Notepad++使用技巧之--把没有html规范格式的html文本变成有缩进的规范格式:下载插件XMLToolsrestartNotepad++选中文本,使用快捷键:Ctrl+Shift+Alt+......
  • MySQL查看库中所有表的大小和记录数
    阅读目录说明说明TABLE_NAME:表名字;DATA_LENGTH:数据大小;INDEX_LENGTH:索引大小;TABLE_ROWS:记录数量;TABLE_SCHEMA:数据库名字;ENGINE:所使用的存储引擎;......
  • 自我介绍与学习记录
    这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzzcxy/2023learning这个作业要求在哪里:https://edu.cnblogs.com/campus/fzzcxy/2023learning/homework/12898这个......
  • OpenGL API学习记录 glBlitFramebuffer
    glBlitFramebuffer将FBO中指定的东西copy到指定地方去配合bind函数使用下面例子拷贝的颜色缓存在延迟渲染时可以拷贝GL_DEPTH_BUFFER_BIT来结合正向渲染和延迟渲染glBin......
  • OpenGL API学习记录glBufferData glBuferSubData glBindBufferRange
    glBufferDataglBufferSubDataglBindBufferRange第一个参数为targetbuffer第二个这个是把buffer的内容进行修改第三个有点像malloc但这个是UBO学到的先设定好第二个参数ind......
  • OpenGL API学习记录glMapBuffer
    除了glBufferSubData还有MapBuffer这种方式来修改数据floatdata[]={0.5f,1.0f,-0.35f...};glBindBuffer(GL_ARRAY_BUFFER,buffer);//获取指针void*ptr=glMapB......
  • MethodParameter
    方法参数是对方法(包括构造方法的)某一个参数(注意是一个参数)或返回值(返回值的parameterindex为-1)的封装......
  • 7、install_mysql_httpd_php_wordpress
    #!/bin/bash##********************************************************************#Author: zikang#QQ: [email protected]#Date: 2021-03-03......