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

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

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

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

于是此时一个很暴力的做法就是预处理出所有合法的连通块,然后状压 \(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. 【机器学*】k*邻算法-01

    k临*算法(解决分类问题): 已知数据集,以及该数据对应类型 给出一个数据x,在已知数据集中选择最接*x的k条数据,根据这k条数据的类型判断x的类型 具体实现: from numpy import * ...

  2. 去除input标签点击时的默认样式

    去除input标签点击时的默认样式的方法 outline:none; //去除点击时的边框 border : none; //去除input框的边框

  3. 使用pypy3加速python运行

    从这里下载对应OS版本的安装包 解压: tar xf pypy-x.y.z.tar.bz2 然后通过./pypy-x.y.z/bin/pypy可以直接进入console 可以使用pip安装包: ./p ...

  4. TortoiseGit使用ssh-keygen生成的私钥

    1.说明 使用TortoiseGit自带的PuTTY Key Generator工具, 把ssh-keygen生成的私钥转换为Putty使用的.ppk文件, 然后在拉取Git代码时, 加载对应的.pp ...

  5. Hangfire任务调度框架使用

    1.HangFire简介 HangFire是一个免费简单实用的分布式后台定时调度服务,在现在.net开发中,人气算是很高的. HangFire提供了内置集成化的控制台,可以直观明了的查看作业调度情况, ...

  6. 接口测试 再也不必来回切换,发现一个接口测试软件,可以替代 Swagger+Mock+Jmeter+Postman

    ​ 前言 日常测试过程中,常常需要多种工具来接力完成自己的接口测试任务. 比如说, 使用swagger查看接口文档, 使用mock编造接口数据对前端页面做测试 使用postman测试后端接口, 用Jm ...

  7. Rainbond 对接 Istio 原理讲解和代码实现分析

    一.背景 现有的 ServiceMesh 框架有很多,如 Istio.linkerd等.对于用户而言,在测试环境下,需要达到的效果是快.开箱即用.但在生产环境下,可能又有熔断.延时注入等需求.那么单一 ...

  8. 计算机系统3-> 现代计算机基石 | 图灵机理论

    在理解CPU之前,我们有必要先了解一下现代计算机理论的基石--图灵机,这个抽象模型决定了现代计算机可以被实现.这个模型的工作原理也投射到了CPU的工作实现上.图灵机的知识可深可浅,换句话说,上手容易, ...

  9. 初识python: random 模块

    random 顾名思义,就是取 随机数,需要导入random模块. import random 1.随机获取一个0到1之间的小数(不含首尾) print(random.random()) 2.随机获取 ...

  10. Tool_BurpSuite安装和简单使用

    一.安装 1.检查Java环境 Burp Suite是用Java语言开发的,运行时依赖于JRE,因此需要先配置Java环境.在CMD中输入java -version 出现下图的结果,证明已配置Java ...