首先,我们需要给一个连通块找到一个直观的合法判定解。

那么我们必须以一种直观的方式将边按照权值分开,这样才能直观地判定一个合法的组。

一个常见的方式是将边从小到大依次加入进来,那么在任意时刻图上存在的边和不存在的边就恰好被一个权值分开了。

那么我们可以很清晰地发现,一个联通块是合法的,当且仅当在上述流程的某个时刻这个连通块会形成一个团。

于是此时一个很暴力的做法就是预处理出所有合法的连通块,然后状压 \(dp\),但这样是指数级的,显然不可取。

看似这个问题已经难以优化了,但你会发现上面这个依次加边的模型非常类似于 \(\rm Kruskal\) 重构树,那么这个 \(dp\) 可不可以在重构树上被优化呢?

那么你会发现上面的这个团只可能是 \(\rm Kruskal\) 重构树上的一颗子树或一个单点,同时这些团也可以在 \(\rm Kruskal\) 的流程中求出。

于是问题就转化为给定一棵树,你需要把这颗树划分成 \(k\) 个联通块,每个可划分的联通块都是给定的的方案。

不难发现这个东西可以直接树形背包 \(O(n ^ 2)\) 解决。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define Next(i, u) for (int i = h[u]; i; i = e[i].next)
const int N = 3000 + 5;
const int M = 1500 + 5;
const int Mod = 998244353;
struct edge { int v, next;} e[N << 1];
int n, tot, cnt, d[N], h[N], sz[N], fa[N], x[M * M], y[M * M], a[M][M], dp[N][M];
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int Inc(int a, int b) { return (a += b) >= Mod ? a - Mod : a;}
int Mul(int a, int b) { return 1ll * a * b % Mod;}
int find(int x) { return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
void add(int u, int v) {
e[++tot].v = v, e[tot].next = h[u], h[u] = tot;
e[++tot].v = u, e[tot].next = h[v], h[v] = tot;
}
void dfs(int u, int fa) {
int a = 0, b = 0;
Next(i, u) {
int v = e[i].v; if(v == fa) continue;
dfs(v, u); if(!a) a = v; else b = v;
}
rep(i, 1, sz[a]) rep(j, 1, sz[b]) dp[u][i + j] = Inc(dp[u][i + j], Mul(dp[a][i], dp[b][j]));
if(d[u] == sz[u] * (sz[u] - 1) / 2) dp[u][1] = 1;
}
int main() {
n = cnt = read();
rep(i, 1, n) rep(j, 1, n) a[i][j] = read(), x[a[i][j]] = i, y[a[i][j]] = j;
rep(i, 1, 2 * n) fa[i] = i, sz[i] = (i <= n);
rep(i, 1, n * (n - 1) / 2) {
int Fx = find(x[i]), Fy = find(y[i]);
if(Fx != Fy) {
d[++cnt] = d[Fx] + d[Fy] + 1, sz[cnt] = sz[Fx] + sz[Fy];
fa[Fx] = fa[Fy] = cnt, add(cnt, Fx), add(cnt, Fy);
}
else ++d[Fx];
}
dfs(cnt, 0);
rep(i, 1, n) printf("%d ", dp[cnt][i]);
return 0;
}

值得一提的是,当我们的做法与某个算法流程本质相同时,可以尝试在这个算法的基础上对我们的做法进行优化。

CF1408G Clusterization Counting的更多相关文章

  1. CodeForces 1408G Clusterization Counting

    题意 给定 \(n\) 个点的无向带权完全图,边权为 \(1\sim\frac{n(n-1)}{2}\).对于满足 \(1\leq k\leq n\) 的每个 \(k\) 求出将原图划分成 \(k\) ...

  2. Solution -「CF 1480G」Clusterization Counting

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 阶完全图,边权为 \(1\sim\frac{n(n-1)}2\) 的排列.称一种将点集划分为 \(k\) ...

  3. 萌新笔记——Cardinality Estimation算法学习(二)(Linear Counting算法、最大似然估计(MLE))

    在上篇,我了解了基数的基本概念,现在进入Linear Counting算法的学习. 理解颇浅,还请大神指点! http://blog.codinglabs.org/articles/algorithm ...

  4. POJ_2386 Lake Counting (dfs 错了一个负号找了一上午)

    来之不易的2017第一发ac http://poj.org/problem?id=2386 Lake Counting Time Limit: 1000MS   Memory Limit: 65536 ...

  5. ZOJ3944 People Counting ZOJ3939 The Lucky Week (模拟)

    ZOJ3944 People Counting ZOJ3939 The Lucky Week 1.PeopleConting 题意:照片上有很多个人,用矩阵里的字符表示.一个人如下: .O. /|\ ...

  6. find out the neighbouring max D_value by counting sort in stack

    #include <stdio.h> #include <malloc.h> #define MAX_STACK 10 ; // define the node of stac ...

  7. 1004. Counting Leaves (30)

    1004. Counting Leaves (30)   A family hierarchy is usually presented by a pedigree tree. Your job is ...

  8. 6.Counting Point Mutations

    Problem Figure 2. The Hamming distance between these two strings is 7. Mismatched symbols are colore ...

  9. 1.Counting DNA Nucleotides

    Problem A string is simply an ordered collection of symbols selected from some alphabet and formed i ...

随机推荐

  1. Jmeter环境变量配置你不得不知道的事情

    在安装Jmeter的过程中大家肯定需要配置环境,但是为什么要配置JDK的环境变量呢?大家有没有好奇过,有没有仔细去像一下呢,其实在安装Jmeter前,大家应该都知道Jmeter是我们JAVA开发的,J ...

  2. CS5216PIN TO PIN替换PS8402A方案|PS8402A电路设计原理图|CS5216芯片

    PS8402A是HDMI 电平移位器/中继器专为2型双模Display Port(DP++)电缆适配器应用而设计.它设计用于Display Port到DVI或Display Port到HDMI的2型适 ...

  3. 生成对抗网络GAN与DCGAN的理解

    作者在进行GAN学习中遇到的问题汇总到下方,并进行解读讲解,下面提到的题目是李宏毅老师机器学习课程的作业6(GAN) 一.GAN 网络上有关GAN和DCGAN的讲解已经很多,在这里不再加以赘述,放几个 ...

  4. 大二 mysql高级+html响应式+Java高级50道试题

    1.CSS3中过渡属性 transition-timing-function的值包括哪些 A. ease B. inline C. ease-in D. easeout 答案:A,C 解析:过渡属性 ...

  5. docker学习:docker镜像

    镜像是什么 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码.运行时.库.环境变量和配置文件. UnionFS(联合文件系 ...

  6. java运算符1

    一:算术运算符(+,  -,   *,  /,  ++,  --, ) 1.+号 :可以做加法运算(加号两边为字符和数字).正数表示 字符串连接符:只要+号两边其中有一边有字符串,输出时加号就充当连接 ...

  7. 自定义djangorestframework-simplejwt的验证表

    django restframework-simplejwt默认是通过调用django的get_user_model方法来得到验证表的表名,然后再通过查询id来验证是否有这个用户. 当需要自定义用户表 ...

  8. 使用 Docker 部署 Seata Server(分布式事务解决方式)

    1.获取镜像 ## 使用下面命令获取最新版本的镜像,此时我的版本是1.3.0 ## 或者可以使用docker pull seataio/seata-server:latest获取最新的镜像 docke ...

  9. post请求后获取不到请求头信息的原因

    在前台获取数据时,因为没有条件,所以不用传数据,用的post请求.再添加token验证时想着前端在请求时直接添加一个请求头信息就ok 没想到后台却获取不到请求头信息,打印了下日志发现是null,这是怎 ...

  10. [ vue ] Quasar封装q-dialog组件,在外层实现弹出框的开启和关闭

    场景描述: 见:https://www.cnblogs.com/remly/p/12981582.html 具体实现: <!-- 父组件 --> <template> < ...