首页 > 其他分享 >Solution - Codeforces 1970G3 Min-Fund Prison (Hard)

Solution - Codeforces 1970G3 Min-Fund Prison (Hard)

时间:2024-08-22 18:49:04浏览次数:7  
标签:连通 frac Min int Hard maxn 1970G3 mathcal low

时间 \(\mathcal{O}(\frac{n\sqrt{n}\log n}{\omega})\) 空间 \(\mathcal{O}(\frac{n\log n}{w})\) 的爆标做法。

首先无解当且仅当图联通且无割边。

首先考虑加边的贡献。
一个比较直观的感受就是只会尽可能少的加边,即加边到整个图连通。

证明考虑删掉的边。
如果加多了边导致删除后不会有两个连通块一定不行;如果加多了边后最后分出的还是两个连通块显然加多的边是不必要的。

于是加边的贡献就好算了,因为加的边的数量一定是连通块数 \(-1\)。

接下来考虑删边后的贡献。
显然的是肯定两部分大小越接近 \(\frac{n}{2}\) 越优。

考虑两部分是如何组成的。
能发现除了有一个连通块会被割边拆开,其他的连通块都会整体留下,并且这些连通块可以任意组合(还有一种情况是选的割边是加的边,即就是连通块任意组合,可以与上一种情况一同处理)。

于是就可以想到用背包的形式,得到去掉某一个连通块其他连通块大小的背包,这显然是可以 bitset 优化的。

于是一个想法就是缺一分治,即分治时把一边贡献到递归下去的另一边处理,但复杂度为 \(\mathcal{O}(\frac{n^2\log n}{\omega})\),还是不太行。

进一步的,考虑到除掉去除的连通块,对于其他的连通块其实只关心其大小。
于是在缺一分治时,实际上只需要考虑对出现过的连通块的大小分治。

具体的,若一种连通块的大小的出现次数 \(c \ge 1\),就可以先将 \(c - 1\) 个用二进制分组的形式放入背包。
那么缺一分治时,实际上涉及到的元素就是连通块的大小了。
大小的种类数是 \(\mathcal{O}(\sqrt{n})\) 的,所以这部分的复杂度是 \(\mathcal{O}(\frac{n\sqrt{n}\log n}{\omega})\)。

接下来优化求解答案。
考虑到因为连通块大小的和 \(= n\),所以可以直接暴力枚举划分情况,令其中一个块划分到的大小为 \(x\),并钦定 \(x\) 所在块大小 \(\ge \lceil\frac{n}{2}\rceil\),再去找这个大小实际是多少。

那么就是找到最靠前的 \(\ge \lceil\frac{n}{2}\rceil - x\) 的位置。

一个想法是判定一下 \(\lceil\frac{n}{2}\rceil - x\) 是否存在,不存在就用 _Find_next,\(\mathcal{O}(\frac{n^2}{\omega})\)。
但是考虑到当 \(x\) 递增时 \(\lceil\frac{n}{2}\rceil - x\) 是递减的,这个最优的位置是可以继承的,就可以先 _Find_next 问出 \(x = 0\) 的情况,然后扫一遍动态维护。

于是这部分复杂度就是 \(\mathcal{O}(n + \frac{n\sqrt{n}}{w})\)。

最后总时间复杂度 \(\mathcal{O}(\frac{n\sqrt n\log n}{\omega})\)。
因为分治的每一层都需要开一个 bitset,空间复杂度 \(\mathcal{O}(\frac{n\log n}{\omega})\)。

#include<bits/stdc++.h>
using ll = long long;
inline ll pw2(int n) {return 1ll * n * n;}
const int maxn = 1e5 + 10;
int n;
std::vector<int> to[maxn];
int dfn[maxn], low[maxn], ins[maxn], stk[maxn], top, dtot;
std::vector<int> S;
std::vector<int> vis[maxn];
int tot[maxn];
std::vector<int> val;
int dfs(int u, int fa) {
   dfn[u] = low[u] = ++dtot, ins[u] = 1, stk[++top] = u;
   int siz = 1;
   for (int v : to[u]) {
      if (v == fa) continue;
      if (! dfn[v]) {
         int siz_ = dfs(v, u); low[u] = std::min(low[u], low[v]);
         if (low[v] > dfn[u])
            S.push_back(siz_);
         siz += siz_;
      } else if (ins[v])
         low[u] = std::min(low[u], dfn[v]);
   }
   if (low[u] == dfn[u]) {
      int t;
      do {
         t = stk[top--], ins[t] = 0;
      } while (t != u);
   }
   return siz;
}
std::bitset<maxn> B[20];
ll ans;
void solve(int l, int r, int dep = 0) {
   if (l == r) {
      int x = val[l], n2 = n + 1 >> 1;
      int w = B[dep]._Find_next(n2);
      for (int i = 0; i <= x; i++) {
         if (n2 >= i && B[dep][n2 - i])
            w = n2 - i;
         if (vis[x][i] && w < maxn)
            ans = std::min(ans, pw2(w + i) + pw2(n - w - i));
      }
      return ;
   }
   int mid = (l + r) >> 1;
   B[dep + 1] = B[dep];
   for (int i = mid + 1; i <= r; i++)
      B[dep + 1] |= B[dep + 1] << val[i];
   solve(l, mid, dep + 1);
   B[dep + 1] = B[dep];
   for (int i = l; i <= mid; i++)
      B[dep + 1] |= B[dep + 1] << val[i];
   solve(mid + 1, r, dep + 1);
}
inline void Main() {
   int m, co; scanf("%d%d%d", &n, &m, &co);
   for (int i = 1; i <= n; i++)
      to[i].clear();
   for (int i = 1, x, y; i <= m; i++)
      scanf("%d%d", &x, &y), to[x].push_back(y), to[y].push_back(x);
   int cnt = 0;
   dtot = 0, memset(dfn, 0, sizeof(int) * (n + 1));
   for (int i = 1; i <= n; i++)
      tot[i] = 0, vis[i].clear();
   val.clear();
   for (int i = 1; i <= n; i++)
      if (! dfn[i]) {
         cnt++; int siz = dfs(i, 0);
         if (! tot[siz]++)
            vis[siz].resize(siz + 1), val.push_back(siz);
         for (int x : S)
            vis[siz][x] = vis[siz][siz - x] = 1;
         vis[siz][0] = vis[siz][siz] = 1;
         S.clear();
      }
   if (cnt == 1) {
      bool fl = 0;
      for (int i = 1; i < n; i++)
         fl |= vis[n][i];
      if (! fl)
         return puts("-1"), void();
   }
   B[0].reset(), B[0].set(0);
   ans = 1e18;
   for (int x = 1; x <= n; x++) {
      if (tot[x]) {
         val.push_back(x);
         int v = tot[x]; v--;
         for (int i = 1; i <= v; v -= i, i <<= 1)
            B[0] |= B[0] << i * x;
         B[0] |= B[0] << v * x;
      }
   }
   solve(0, val.size() - 1);
   printf("%lld\n", 1ll * co * (cnt - 1) + ans);
}
int main() {
   int T; scanf("%d", &T);
   while (T--) Main();
   return 0;
}

标签:连通,frac,Min,int,Hard,maxn,1970G3,mathcal,low
From: https://www.cnblogs.com/rizynvu/p/18374511

相关文章

  • 我一直在X上试用Grok-2——它确实是ChatGPT和Gemini的有力竞争对手
    Grok-2是一个内置于X平台并通过其内容训练的人工智能聊天机器人,现在已经进入了beta版,这是其前身的巨大进步,使其跻身于领先的AI聊天工具之列,与ChatGPT、Claude和GoogleGemini等齐名。在发布后不久,Grok-2进入了LMSys聊天机器人竞技场排行榜的前五名。这些是对领先LLMs的人工评......
  • C++版的Minecraft
    非常垃圾的c++版Mc.#include<bits/stdc++.h>#include<windows.h>#include<conio.h>usingnamespacestd;typedefstructFrame{COORDposition[2];}Frame;voidColor(inta){//白if(a==0)SetConsoleTextAttribute(GetStdHandle(STD_O......
  • YC327A [ 20240821 CQYC NOIP 模拟赛 T1 ] 最值(minmax)
    题意对于一个序列\({b_n}\),规定:\[f_min(b)=\prod_{i=1}^n(min_{j=1}^ib_j)\]\[f_max(b)=\prod_{i=1}^n(max_{j=1}^ib_j)\]给定一个序列\(a\),求\(a\)所有的排列\(p\)的\(f_min(p)\)与\(f_max(p)\)之和。\(n\le5000\)Sol不难想到一个简......
  • mini-lsm通关笔记Week1Day4
    项目地址:https://github.com/skyzh/mini-lsm个人实现地址:https://gitee.com/cnyuyang/mini-lsmTask1-SSTBuilder在此任务中,您需要修改:src/table/builder.rssrc/table.rsSST由存储在磁盘上的数据块和索引块组成。通常,数据块都是懒加载的-直到用户发出请求,它们才会被加载......
  • A Comparative Study of AI-Generated (GPT-4) and Human-crafted MCQs in Programmin
    文章目录题目摘要引言相关工作数据集MCQ生成提示实验设计结果讨论对教学实践的启示有效性的局限性和威胁结论和未来工作题目编程教育中人工智能生成的(GPT-4)和人类编写的MCQ的比较研究论文地址:https://dl.acm.org/doi/10.1145/3636243.3636256摘要    ......
  • STAT 311 Programming
    Programming Assignment 8STAT 311Pleasecompletethefollowingproblemsand submit a file named STAT311-HW8 .R to Gradescope.Youshouldstart from the provided STAT311-HW8 .R file on Canvas.OverviewAddress each of the following que......
  • 两幅图像间的比较运算,可实现抠图和通道选择:max( ) min( )
    学OpenCV==============================================通过掩模,可以实现抠图和通道选择的效果。这里用的是min============================================== 1#include<iostream>23#include<opencv2/opencv.hpp>4#include<opencv2/core/utils/log......
  • 修改$ORACLE_HOME/network/admin/sqlnet.ora
    原因分析:网上查了主要是说我电脑上orcale的客户端版本和访问的oracle服务端的版本不一致,但我连接的是本地数据库,应该不存在该问题。保险起见,我先在网上找了相关问题的讨论,大家提出的常用解决方案是修改$ORACLE_HOME/network/admin/sqlnet.ora文件里的参数配置,对于该方法跟我的问......
  • Windows安装与启动Minio文件存储桶
    需要选择开源版本,不然报错,需要授权文件需要命令启动C:\minio.exeserverE:\minio\data--console-address"127.0.0.1:9000"--address"127.0.0.1:9005"显示账号密码首先需要创建桶,并上传文件,可以进行共享参考:https://blog.csdn.net/m0_54230514/article/details/138337......
  • [ABC156E] Roaming 题解
    前言这哪有蓝,评分似乎有点过了。思路既然是要统计每个房间人数的排列,那我们就枚举把所有人都放到\(i\)个房间里的方案数,这个用插板法解决,把所有人都放到\(i\)个房间里也就是把他们分成\(i\)份,这一部分的答案就是在\(n\)个人的\(n-1\)个空中插入\(i-1\)块隔板的方案......