http://uoj.ac/problem/279

先判断答案为0的情况,\(d(i,i)\neq 0\),\(d(i,j)\neq d(j,i)\),\(d(i,j)>d(i,k)+d(k,j)\),\(d(i,j)>k\)。

对于\(d(i,j)>0\)的情况,如果存在\(k\neq i,j\)且满足\(d(i,j)=d(i,k)+d(k,j)\),那么i和j的边就可以取d(i,j)~k的所有权值,答案乘上\(k-d(i,j)+1\)即可。

如果存在\(d(i,j)=0\)的情况,用并查集把最短距离为0的点缩起来,形成许多连通块。两个连通块之前会有很多边,且这些边的d值相同。把连通块看成一个点,那么就成了上一行的问题中有d值相同重边的情况;设ij之间的重边数为a,这个情况中如果存在上一行所述的k,答案乘上\((k-d(i,j)+1)^a\);如果不存在上一行所述的k,答案乘上\((k-d(i,j)+1)^a-(k-d(i,j))^a\)。

对于每个连通块内的方案数,假设连通块大小为n,设边权为0的边连通整个连通块的方案数为\(f(n)\),不管连不连通所有边权任意的方案数为\(g(n)\),因为这个连通块是个完全图,所以\(g(n)=(k+1)^{\frac{n(n-1)}2}\),同时:$$f(n)=g(n)-\sum_{i=1}^{n-1}f(i)g(n-i)

\begin{pmatrix}n-1\i-1\ \end{pmatrix} k^{i(n-i)}$$

先定住一个连通块内的点x,转移时枚举包括x的连通块的大小\(f(i)\)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 403;
const int p = 998244353; int fa[N], d[N][N], n, k, F[N], G[N], jc[N], jcn[N], cnt[N][N], sum[N]; inline int ipow(int a, int b) {
int r = 1, w = a;
while (b) {
if (b & 1) r = 1ll * r * w % p;
b >>= 1;
w = 1ll * w * w % p;
}
return r;
} inline int C(int a, int b) {return 1ll * jc[a] * jcn[b] % p * jcn[a - b] % p;}
inline void sub(int &a, int b) {a -= b; if (a < 0) a += p;} int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
inline void merge(int a, int b) {
if ((a = find(a)) != (b = find(b)))
fa[a] = b;
} int ans = 1; int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
scanf("%d", &d[i][j]);
if (d[i][j] > k) {puts("0"); return 0;}
} for (int i = 1; i <= n; ++i) {
if (d[i][i] != 0) {puts("0"); return 0;}
for (int j = i + 1; j <= n; ++j)
if (d[i][j] != d[j][i])
{puts("0"); return 0;}
} for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
for (int kk = 1; kk <= n; ++kk)
if (d[i][j] > d[i][kk] + d[kk][j])
{puts("0"); return 0;} jc[0] = jcn[0] = 1;
for (int i = 1; i <= n; ++i) {
jc[i] = 1ll * jc[i - 1] * i % p;
jcn[i] = ipow(jc[i], p - 2);
} for (int i = 1; i <= n; ++i) {
F[i] = G[i] = ipow(k + 1, i * (i - 1) / 2);
for (int j = 1; j < i; ++j)
sub(F[i], 1ll * F[j] * G[i - j] % p * C(i - 1, j - 1) % p * ipow(k, j * (i - j)) % p);
} for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j)
if (d[i][j] == 0)
merge(i, j); int u, v;
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j)
if ((u = find(i)) != (v = find(j)))
++cnt[u][v], ++cnt[v][u]; int a;
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j)
if (a = cnt[i][j]) {
bool flag = false;
for (int kk = 1; kk <= n; ++kk)
if (cnt[i][kk] && cnt[kk][j] && d[i][j] == d[i][kk] + d[kk][j]) {
flag = true;
break;
}
if (flag) ans = 1ll * ans * ipow(k - d[i][j] + 1, a) % p;
else ans = 1ll * ans * ((ipow(k - d[i][j] + 1, a) - ipow(k - d[i][j], a) + p) % p) % p;
} for (int i = 1; i <= n; ++i) ++sum[find(i)];
for (int i = 1; i <= n; ++i)
if (sum[i]) ans = 1ll * ans * F[sum[i]] % p;
printf("%d\n", ans);
return 0;
}

【UOJ #279】【UTR #2】题目交流通道的更多相关文章

  1. 【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升

    [UOJ#278][UTR #2]题目排列顺序 试题描述 “又要出题了.” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这 ...

  2. uoj#279. 【UTR #2】题目交流通道(容斥+数数)

    传送门 先考虑无解的情况,为以下几种:\(dis_{i,j}+dis_{j,k}<dis_{i,k}\),\(dis_{i,i}\neq 0\),\(dis_{i,j}\neq dis_{j,i ...

  3. UOJ279 【UTR #2】题目交流通道

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000  作者博客:http://www.cnblogs.com/ljh2000-jump ...

  4. 【UTR #2】题目交流通道

    题目描述 定好了难度,雄心勃勃的吉米多出题斯基开始寻找智慧的神犇星球的居民出题. 然而吉米多出题斯基没有料到,神犇星球的居民告诉吉米多出题斯基:"今年神犇星球经济不景气,大家都想宅在家里,哪 ...

  5. uoj279题目交流通道(dp)

    题目大意: 神犇星球有 \(n\) 座小城.对于任意两座小城 \(v,u\)\((v≠u)\),吉米多出题斯基想在 \(v,u\) 之间建立一个传送时间为 \(w(v,u)\)的无向传送通道,其中 \ ...

  6. uoj279 题目交流通道

    题目:告诉你每两个点之间的最短路距离.构造每条边边权<=m的无向完全图.求有多少种不同边权的图满足最短路限制?n<=400. 标程: #include<cstdio> #inc ...

  7. 【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set

    题目描述 给出 $n$ 个数 $a_1,a_2,...,a_n$ ,将其排为序列 $\{p_i\}$ ,满足 $\{前\ i\ 个数的中位数\}$ 单调不降.求字典序最大的 $\{p_i\}$ . 其 ...

  8. UOJ Test Round #2

    昨天晚上打的这个比赛,简直一颗赛艇啊-- 感觉发挥的并不好.比赛的时候比较紧张,最后一题还脑残写了个离散化结果爆零了,哎我怎么这么逗逼-- 讲讲比赛经过吧. 比赛之前逗逼地以为是8:00开始,然后淡定 ...

  9. 「总结」$dp1$

    大概就是做点题. 先列一下要做的题目列表,从\(UOJ\)上找的. 129寿司晚宴 348州区划分 370滑稽树上滑稽果 457数树 22外星人 37主旋律 300吉夫特 196线段树 311积劳成疾 ...

随机推荐

  1. python学习笔记(三)之变量和字符串

    在其他语言中,变量就是有名字的存储区,可以将值存储在变量中,也即内存中.在Python中略有不同,python并不是将值存储在变量中,更像是把名字贴在值上边.所以,有些python程序员会说pytho ...

  2. 大聊Python----协程

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来 ...

  3. Winform Socket通信

    Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...

  4. js_判断当前页面是否有网络和网络连接超时

    2018-04-12 方法一:通过navigator.onLine属性判断,返回true为有联网状态,false为断网状态. //方法一 if(navigator.onLine) { console. ...

  5. js_参数的get传输,从一个页面到另外一个页面。

    2017年10月31日,今天是万圣节,欢乐谷搞事情. 刚接触前端那会是分不清,前端和后台的,后台的数据如何传输到前端的. 现在用的还是Jquery的ajax请求后台数据到前端页面的,需要学习的地方还有 ...

  6. Java爬取网易云音乐民谣并导入Excel分析

    前言 考虑到这里有很多人没有接触过Java网络爬虫,所以我会从很基础的Jsoup分析HttpClient获取的网页讲起.了解这些东西可以直接看后面的"正式进入案例",跳过前面这些基 ...

  7. linux下守护进程的创建

    最近在学习linux c编程 看到了守护进程的创建,感觉很好玩, 测试环境ubuntu 15.04 下面贴出测试代码 #include <stdio.h> #include <std ...

  8. [Leetcode Week14]Construct Binary Tree from Inorder and Postorder Traversal

    Construct Binary Tree from Inorder and Postorder Traversal 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/pr ...

  9. python实战===一句python代码搭建FTP服务

    环境搭建: python windows/linux pip install pyftpdlib  (安装失败请到这里下载:https://pypi.python.org/pypi/pyftpdlib ...

  10. Redis 主从部署

    Redis 主从部署 http://www.xuchanggang.cn/archives/978.html