CodeForces 1408G Clusterization Counting
题意
给定 \(n\) 个点的无向带权完全图,边权为 \(1\sim\frac{n(n-1)}{2}\)。对于满足 \(1\leq k\leq n\) 的每个 \(k\) 求出将原图划分成 \(k\) 个组的方案数,满足组间边的权大于组内边的权值,答案对 \(998244353\) 取模。
\(\texttt{Data Range:}1\leq n\leq 1500\)
题解
这个题蛮好的,只是我赛时没有想出来(甚至差点没有看懂题目),果然还是我太菜了/kk
首先从小到大把边加进来,然后可以发现一个结论:一个连通块是满足条件的当且仅当在加完某条边之后这个连通块是一个团。
这个时候可以直接用类似于 Kruskal 的方法:从小到大加边,并查集维护一下这个连通块的大小和边数,当加完某条边时候可以满足这个连通块是一个团的话就标记一下这个连通块是可以的。
这个时候好像是可以 DP 了,但是复杂度会爆炸。
考虑优化一下,在从小到大加边的过程中考虑 Kruskal 重构树。由于重构树新加的节点维护的是一个连通块,其叶子节点是连通块中所有的节点,所以可以对重构树进行 dfs,用一段区间表示一个连通块。
于是现在变成了有一些区间,要从中选出 \(k\) 个覆盖 \(1\sim n\) 的所有位置。把所有区间挂到右端点上,设 \(f_{i,j}\) 表示当前位置为 \(i\) 并且钦定当前最后一个区间右端点为 \(i\),选出了 \(j\) 个区间的答案,转移的时候枚举一下最后一个区间的左端点是什么就没了。
时间复杂度 \(O(n^2\log n)\),主要瓶颈在排序上。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=3e3+51,MOD=998244353;
struct EdgeForKruskal{
ll from,to,dist;
inline bool operator <(const EdgeForKruskal &rhs)const
{
return this->dist<rhs.dist;
}
};
EdgeForKruskal ed[MAXN*MAXN];
ll n,m,idx,u,v,itvc;
ll x[MAXN][MAXN],f[MAXN][MAXN],ffa[MAXN],sz[MAXN],edc[MAXN];
ll l[MAXN],r[MAXN],flg[MAXN];
vector<ll>g[MAXN],itv[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline ll find(ll x)
{
return ffa[x]==x?x:ffa[x]=find(ffa[x]);
}
inline void add(ll x)
{
if((++edc[x])==sz[x]*(sz[x]-1)/2)
{
flg[x]=1;
}
}
inline void dfs(ll x)
{
if(x<=n)
{
return (void)(l[x]=r[x]=++itvc);
}
l[x]=n+1;
for(register int to:g[x])
{
dfs(to),l[x]=min(l[x],l[to]);
}
r[x]=itvc,flg[x]?itv[r[x]].push_back(l[x]):(void)1;
}
int main()
{
n=read(),f[0][0]=1;
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
x[i][j]=read();
j>i?(void)(ed[++m]=(EdgeForKruskal){i,j,x[i][j]}):(void)1;
}
}
idx=n,sort(ed+1,ed+m+1);
for(register int i=1;i<=n;i++)
{
flg[i]=1,itv[i].push_back(i),ffa[i]=i,sz[i]=1,edc[i]=0;
}
for(register int i=1;i<=m;i++)
{
u=find(ed[i].from),v=find(ed[i].to);
if(u==v)
{
add(u);
}
else
{
g[++idx].push_back(u),g[idx].push_back(v);
ffa[u]=ffa[v]=ffa[idx]=idx;
sz[idx]=sz[u]+sz[v],edc[idx]=edc[u]+edc[v],add(idx);
}
}
dfs(idx);
for(register int i=1;i<=n;i++)
{
for(register int j=1;j<=n;j++)
{
for(register int k:itv[i])
{
f[i][j]=(f[i][j]+f[k-1][j-1])%MOD;
}
}
}
for(register int i=1;i<=n;i++)
{
printf("%d ",f[n][i]);
}
}
CodeForces 1408G Clusterization Counting的更多相关文章
- Codeforces 954H Path Counting 【DP计数】*
Codeforces 954H Path Counting LINK 题目大意:给你一棵n层的树,第i层的每个节点有a[i]个儿子节点,然后问你树上的简单路径中长度在1~n*2-2之间的每个有多少条 ...
- Codeforces 372 B. Counting Rectangles is Fun
$ >Codeforces \space 372 B. Counting Rectangles is Fun<$ 题目大意 : 给出一个 \(n \times m\) 的 \(01\) ...
- 【codeforces 335E】 Counting Skyscrapers
http://codeforces.com/problemset/problem/335/E (题目链接) 题意 懒得写了= = Solution 这题咋不上天= =. 参考题解:http://blo ...
- Codeforces 911D. Inversion Counting (数学、思维)
题目链接:Inversion Counting 题意: 定义数列{ai|i=1,2,...,n}的逆序对如下:对于所有的1≤j<i≤n,若ai<aj,则<i,j>为一个逆序对. ...
- Codeforces 954H Path Counting(DP)
题目链接 Path Counting 题意 给定一棵高度为$n$的树,给出每一层的每个点的儿子个数(某一层的所有点儿子个数相同). 令$f_{k}$为长度为$k$的路径条数,求$f_{1}, ...
- CodeForces - 990G GCD Counting
Discription You are given a tree consisting of nn vertices. A number is written on each vertex; the ...
- 【Codeforces 372A】Counting Kangaroos is Fun
[链接] 我是链接,点我呀:) [题意] 如果a[i]*2<=a[j]那么i袋鼠可以装进j袋鼠里面 每只袋鼠都只能装一只袋鼠 [题解] 假设最后的方案是(ai,bi) 这里(ai,bi)表示下标 ...
- CodeForces 372 A. Counting Kangaroos is Fun
题意,有n只袋鼠,没每只袋鼠有个袋子,大小为si,一个袋鼠可以进入另外一个袋鼠的袋子里面,当且仅当另一个袋鼠的袋子是他的二倍或二倍一上,然后中国袋鼠就是不可见的,不能出现多个袋鼠嵌套的情况.让你求最少 ...
- CF1408G Clusterization Counting
首先,我们需要给一个连通块找到一个直观的合法判定解. 那么我们必须以一种直观的方式将边按照权值分开,这样才能直观地判定一个合法的组. 一个常见的方式是将边从小到大依次加入进来,那么在任意时刻图上存在的 ...
随机推荐
- IOT(esp8266)
今日工具: 硬件: esp8266 DHT11温湿度传感器 软件: Arduino ESP8266 是一款由乐鑫 Espressif 公司制作的低成本的 Wi-Fi 芯片,具有完整的 TCP / IP ...
- 035 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 02 多重if结构
035 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 02 多重if结构 本文知识点:Java中的多重if结构 选择结构回顾 if选择结构 注意: 1.条 ...
- puts()和gets()函数
puts()和gets()函数 1. puts()函数 puts()函数用来向标准输出设备(屏幕)写字符串并换行, 其调用格式为: puts(s); 其中s为字符串变量(字符串数组名或字符串指针). ...
- MATLAB textread函数
实际应用中经常要读取txt文件,这个时候就需要用到强大的textread函数.它的基本语法是:[A,B,C,...] = textread(filename,format)[A,B,C,...] = ...
- Centos下Oracle11gR2安装教程与自动化配置脚本
系统环境准备 开发组件与依赖库安装 安装centos时选择Server with GUI,右面的可以不勾选,后面统一来装 配置本地yum源 以上包如果缺乏可配置本地yum源进行安装 sudo moun ...
- OAuth 2.0 Server PHP实现示例
需求实现三方OAuth2.0授权登录 使用OAuth服务OAuth 2.0 Server PHP 环境nginx mysqlphp 框架Yii 一 安装 项目目录下安装应用 composer.phar ...
- 多测师讲解自动化测试 _RF模拟鼠标悬停_高级讲师肖sir
test19 Open Browser https://www.ctrip.com/?sid=155952&allianceid=4897&ouid=index gc Maximize ...
- ASP.Net Core3.1 生成二维码填坑
ASP.Net Core3.1 使用QrCode生成二维码 部署到Linux报错 The type initializer for 'System.DrawingCore.GDIPlus' threw ...
- v-model数据绑定分析
v-model数据绑定分析 v-model是Vue提供的指令,其主要作用是可以实现在表单<input>.<textarea>及<select>等元素以及组件上创建双 ...
- VMware虚拟机中共享文件夹 开机启动
输入命令: sudo /usr/bin/vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other -o uid=1000 -o gid=1000 -o umask=02 ...