1400G - Mercenaries

考场上想到枚举,但是只想到了 \(2 ^ m\) 枚举矛盾,然后用 NOI Online 2 游戏 类似的容斥掉,结果式子推着推着就复杂度爆了 wtcl。

(Update:后来看其它大佬的博客是可以的,下面的内容是抄的neal的题解)

如果我们把一个矛盾关系 \((a, b)\) ,在图论意义上连一条边,每个人看作一个点。

这个问题变成了一个独立集计数(还要满足人数限制的)问题。

显然,每个连通图的方案是独立的。

由于有人数限制,我们可以想到枚举人数 \(x\),算 \(x\) 人的独立集个数,我们可以把每个连通图看作一个整体,剩下的看作一个整体。我们把每个连通图的人数看作体积,价值为方案数,把所有连通图做一遍分组背包,然后剩余的点用组合数就好,然后算出剩下的人数(用简单的差分预处理 + 简单的组合数)。

那么对于一个连通图 \(i\) 和人数 \(j\),设 \(h_{i, j, k}\) 为总人数恰好为 \(j\) 人,从 \(i\) 连通图选出 \(k\) 个相互不冲突的人数的方案数。那么怎么预处理出这个东西呢?

关注到此题的突破口是 \(m \le 20\),那么最大的连通图最多有 \(m + 1 \le 21\) 个点。那么对于每个 \(i, j\),我们可以先把满足人数限制的点集 \(S_{i, j}\) 找出来,那么就是从 \(S\) 中选 \(k\) 个互不冲突,我们可以再设 \(g_{i, S, k}\) 表示从 \(i\) 连通图的 \(S\) 点集中选 \(k\) 个的方案,这样 \(h_{i, j, k} = g_{i, S_{i, j}, k}\)。怎么算 \(g\)?对于有 \(k\) 个点的连通图,我们可以 \(O(2 ^ k(k + m))\) 枚举选了的点集,判断这个连通图是否没有矛盾,赋值 \(g_{i, S, |S|} = 1\),然后最外层循环一位 0 位置在 \(p\),\(g_{i, S \or 2^p, k} \gets g_{i, S, k}\),这样就可以 \(O(2^kk^2)\) 线性递推了。(注意必须最外层循环,这个的话,可以理解为认为规定了“补0”的顺序,这样方案才不会重复,否则比如00,00->01->11; 00 -> 10 -> 11 会产生重复方案)

设联通块有 \(s\) 个,第 \(i\) 个联通块大小是 \(s_i\)。总时间复杂度 \(O(\displaystyle \sum_{i=1}^s (s_i^2 + m) 2 ^{s_i} + s_in(\sum_{j=1}^{i-1}s_j))\)

前者最大是 \(2 ^ {21} \times 401 \approx 8 \times 10 ^ 8\),后者最大大概是 \(3 \times 10^5 \times 40^2 \approx 5 \times 10^8\)。时间限制是 \(7s\) 所以貌似可以过,并且很多状态似乎无用可以减掉,总之就过了,玄学。。

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std; typedef long long LL; const int N = 300005, P = 998244353, S = 21; int n, m, L[N], R[N], a[N], b[N], g[1 << S][S + 1], c[N], d[N], e[N];
int fact[N], infact[N], f[N][S * 2], tot, fa[N], sz[N], Log[1 << S], now[N], ans; bool vis[N], ins[N];
vector<int> col[N]; int inline power(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = (LL)res * a % P;
a = (LL)a * a % P;
b >>= 1;
}
return res;
} int inline C(int a, int b) {
if (a < b || a < 0 || b < 0) return 0;
return (LL)fact[a] * infact[b] % P * infact[a - b] % P;
} int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
} int main() {
scanf("%d%d", &n, &m); fact[0] = infact[0] = 1;
for (int i = 1; i <= n; i++)
fact[i] = (LL)fact[i - 1] * i % P;
infact[n] = power(fact[n], P - 2);
for (int i = n - 1; i; i--)
infact[i] = (LL)infact[i + 1] * (i + 1) % P; for (int i = 0; i <= 20; i++) Log[1 << i] = i;
for (int i = 1; i <= n; i++) {
scanf("%d%d", L + i, R + i);
f[i][0] = 1, fa[i] = i, sz[i] = 1;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", a + i, b + i);
fa[find(a[i])] = find(b[i]);
ins[a[i]] = ins[b[i]] = true;
}
for (int i = 1; i <= n; i++) {
if (!ins[i]) c[L[i]]++, c[R[i] + 1]--;
}
for (int i = 1; i <= n; i++) col[find(i)].push_back(i), c[i] += c[i - 1];
for (int t = 1; t <= n; t++) {
if (find(t) != t || col[t].size() == 1) continue;
int k = col[t].size();
for (int i = 1; i < (1 << k); i++)
for (int j = 0; j <= k; j++) g[i][j] = 0;
for (int i = 1; i < (1 << k); i++) {
bool ok = true; int cnt = 0;
for (int j = 0; j < k; j++)
if (i >> j & 1) vis[col[t][j]] = true, cnt++;
for (int j = 1; j <= m; j++)
if (vis[a[j]] && vis[b[j]]) { ok = false; break; }
for (int j = 0; j < k; j++)
if (i >> j & 1) vis[col[t][j]] = false;
if (ok) g[i][cnt] = 1;
}
for (int v = 0; v < k; v++) {
for (int i = 1; i + 1 < (1 << k); i++) {
for (int j = 1; j <= k; j++) {
if (!g[i][j] || i >> v & 1) continue;
(g[i + (1 << v)][j] += g[i][j]) %= P;
}
}
}
for (int i = 1; i <= n; i++) d[i] = 0, e[i] = 0;
for (int i = 0; i < k; i++) {
d[L[col[t][i]]] += 1 << i, d[R[col[t][i]] + 1] -= 1 << i;
e[L[col[t][i]]] ++, e[R[col[t][i]] + 1]--;
}
for (int i = 1; i <= n; i++) {
d[i] += d[i - 1], e[i] += e[i - 1];
now[i] += e[i];
for (int j = now[i]; j; j--) {
for (int v = 1; v <= min(j, e[i]); v++) {
if (!f[i][j - v] || !g[d[i]][v]) continue;
f[i][j] = (f[i][j] + (LL)f[i][j - v] * g[d[i]][v]) % P;
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= now[i]; j++) {
ans = (ans + (LL)f[i][j] * C(c[i], i - j)) % P;
}
}
printf("%d\n", ans);
return 0;
}

CF1400G - Mercenaries的更多相关文章

  1. CF 1400G.Mercenaries 题解【SOSDP 组合数学】

    CF 1400G.Mercenaries 题意: 有\(n\)个佣兵,问雇佣至少一名雇佣兵且满足下述条件的方案数 如果雇佣第\(i\)个佣兵必须要求最终雇佣的总人数\(x\)满足\(l_i\le x\ ...

  2. sis9280触摸ic 基于rk3288 的安卓4.4的 多点触摸

    前言:sis提供的驱动ic.基于rk3288的安卓系统.亲眼看到人家完成一次移植.很激动的记下一些东西..虽然我看不懂.其实现在的工作也不需要看懂.叫人协助就好,只需要知道有这个东西. 1linux下 ...

  3. usb.ids

    # # List of USB ID's # # Maintained by Vojtech Pavlik <vojtech@suse.cz> # If you have any new ...

  4. China-global view

    Good morning everyone. Everyone here would know this year Xia’Men held the BRICS business forum.In a ...

  5. CODE大全大量Flash网站收藏

    我的博客:CODE大全:www.codedq.net:业余草:www.xttblog.com:爱分享:www.ndislwf.com或ifxvn.com. http://www.wallop.com在 ...

  6. CentOS 7 Docker基本特性

    Docker是一个开源的应用容器引擎,开发人员可以非常容易地打包已经开发好的应用,同时将应用相关的依赖包也打包到这样一个可移植的容器中,然后发布到任意的Linux主机系统上.Docker是基于Linu ...

  7. ssh整合思想 Spring分模块开发 crud参数传递 解决HTTP Status 500 - Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or(增加事务)

    在Spring核心配置文件中没有增加事务方法,导致以上问题 Action类UserAction package com.swift.action; import com.opensymphony.xw ...

  8. ssh整合思想 Spring与Hibernate和Struts2的action整合 调用action添加数据库 使用HibernateTemplate的save(entity)方法 update delete get 等方法crud操作

    UserAction类代码: package com.swift.action; import com.opensymphony.xwork2.ActionSupport; import com.sw ...

  9. 【洛谷4920】[WC2015] 未来程序(提答题)

    点此看题面 大致题意: 把\(10\)个点的暴力代码和输入数据都给你,让你求出输出数据. 子任务\(1\) 第一个子任务自然是拿来送分用的... 容易发现就是一个快速乘的过程啊. 代码如下: #inc ...

随机推荐

  1. Golang调度器GMP原理与调度全分析(转 侵 删)

    该文章主要详细具体的介绍Goroutine调度器过程及原理,包括如下几个章节. 第一章 Golang调度器的由来 第二章 Goroutine调度器的GMP模型及设计思想 第三章 Goroutine调度 ...

  2. Maximum Subarray(最大连续子串)

    1 class Solution { 2 public: 3 //动态规划,维护两个变量 local[i+1]=max(array[i],local[i]+array[i+1]) 4 int Find ...

  3. 剑指offer刷题(Tree)

    开篇 二刷剑指offer了,本来用Tyora记的笔记,发现字数到四万了就变得好卡o(╥﹏╥)o,刚好开始写博客,就转过来吧,记下来子自己看.不废话,开刷... JZ26. 树的子结构 输入两棵二叉树A ...

  4. pytorch框架对RTX 2080Ti RTX 3090的支持与性能测试

    时间点:202011-18 一.背景 2020年9月nvidia发布了30系列的显卡.比起20系列网上的评价是:性能翻倍,价格减半. 最近正好本人手上有RTX 2080Ti 和 RTX 3090,所以 ...

  5. 众所周知,B站并不是个学习网站

    立了一个Flag鸽鸽鸽鸽 我喜立Flag,9月份说要做点视频,不知不觉已经鸽了俩月了.中间就零星时间学了一些剪辑方面的知识,工作太忙,视频一直没有实质进展.视频的灵魂其实是脚本,到现在还没写好.我还是 ...

  6. C# 中的本地函数

    今天我们来聊一聊 C# 中的本地函数.本地函数是从 C# 7.0 开始引入,并在 C# 8.0 和 C# 9.0 中加以完善的. 引入本地函数的原因 我们来看一下微软 C# 语言首席设计师 Mads ...

  7. MathType中怎么编辑韩文字符

    用MathType编辑公式,所涉及到符号与字母一般都是英文字母与数字,或者使用希腊字母,当然还有很多使用中文的情况.但是不仅如此,我们在使用MathType时,除了这些字符之外,还可以输入韩文或者日文 ...

  8. FL studio系列教程(九):FL Studio中如何排列编曲

    在FL Studio水果音乐制作软件播放列表中可以对制作的样本进行编排,除此之外,播放列表中排列的对象被叫做剪辑.在其中可以排列以下剪辑. 1.样本剪辑:样本剪辑包含了编排好的插件乐器音符数据. 2. ...

  9. 适合 Java 新手的开源项目集合——在 GitHub 学编程

    作者:HelloGitHub--老荀 当今互联网份额最大的编程语言是哪一个?是 Java!这两年一直有听说 Java 要不行了.在走下坡路了.没错,Java 的确在走下坡路,未来的事情的确不好说,但是 ...

  10. MIT-6.005软件构建

    L01 Static Typing 主要对比Java和Python Java:静态语言,运行之前所有变量都要声明.traps:整型相除还是整型,5/2=2.数值溢出,20亿*2结果是负数,这个bug不 ...