[TC_SRM_460]TheCitiesAndRoadsDivOne

试题描述

John and Brus have become very famous people all over the world, especially in Bolivia. Once they decided to visit their fan club in Bolivia. John has an old map of Bolivia which shows all of its cities and the roads connecting them. All roads are bidirectional, meaning they can be traversed in both directions. Since the map is old, it's possible that some additional roads have been built since the map was produced. However, roads are never destroyed in Bolivia, so all the roads on the map still exist.

Brus has discovered on the Internet that each pair of Bolivian cities now has at least one and at most two simple paths connecting them. A path between cities \(A\) and \(B\) is a sequence of cities starting with \(A\) and ending with \(B\) such that there's a road between each pair of consecutive cities in the sequence. The path is considered simple if it consists of distinct cities.

John and Brus have decided to add some new roads to the old map in such a way that the resulting map satisfies this condition. They can only add a road between a pair of cities if that road did not already exist in the old map. They can't add more than one road between the same pair of cities, and they can't add a road that leads from a city to itself. All added roads must be bidirectional.

You are given a map. The \(j\)-th character of the \(i\)-th element of map will be Y if there is a road between the \(i\)-th and \(j\)-th cities on the old map, or N otherwise. Return the number of ways John and Brus can add new roads to the old map modulo \(1234567891\). Two ways are considered different if the sets of added roads are distinct. The order in which roads are added does not matter.

给一个 \(n\)(\(\le 20\))个节点的无向图,求加一些边使得图成为一棵树或者一棵单环树的方案数(答案对 \(1234567891\) 取模)。

输入

传给你一个 string[] 类型的参数

输出

返回一个整数表示答案

输入示例1

{"NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN", "NNNNNNNNNNNN"}

输出示例1

Returns: 1137797187

输入示例2

{"NYYNN", "YNYNN", "YYNNN", "NNNNY", "NNNYN"}

输出示例2

Returns: 6

数据规模及约定

见“试题描述

题解

如果只需要组成树而不是单环树,那么就是明明的烦恼这题,prufer 序列即可,注意每个连通块缩成一个点后需要加权,因为它们大小不一。

这道题我们受它启发,当有一个环的时候,我们枚举哪些连通块组成了一个环,然后组成环的方案乘上接下来组成树的方案(仍可用 prufer 序列计算)就可以了。

注意这题有很多情况需分类讨论(以下只强调特殊情况):

  • 图中已经包含了一个环(这类情况中还需注意所有点都连成了同一个连通分量的情况);

  • 连成环的连通分量只有 \(1\) 个(如果这个连通分量大小小于 \(3\) 则不能用这个连通分量创造环);

  • 连城环的连通分量只有 \(2\) 个(需要考虑重边问题)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--) int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 25
#define maxs 1048576
#define MOD 1234567891
#define LL long long class TheCitiesAndRoadsDivOne {
private:
char str[maxn];
int n, fa[maxn], siz[maxn], Siz[maxn], cntb;
bool hasc[maxn];
int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); } LL Pow(int a, int b) {
LL ans = 1, t = a;
while(b) {
if(b & 1) (ans *= t) %= MOD;
(t *= t) %= MOD; b >>= 1;
}
return ans;
} int cbit[maxs], Log[maxs], fac[maxn]; public:
int find(vector <string> field) {
n = field.size();
fac[0] = 1;
rep(i, 1, n) fa[i] = i, siz[i] = 1, fac[i] = (LL)fac[i-1] * i % MOD;
rep(i, 1, n) {
strcpy(str + 1, field[i-1].c_str());
rep(j, 1, n) if(i < j && str[j] == 'Y') {
int u = findset(i), v = findset(j);
if(u == v) hasc[u] = 1;
else fa[v] = u, siz[u] += siz[v];
}
} bool cyc = 0;
rep(i, 1, n) if(findset(i) == i) Siz[cntb++] = siz[i], cyc |= hasc[i];
LL ans;
if(cntb == 1) ans = 1;
else {
ans = Pow(n, cntb - 2);
rep(i, 0, cntb - 1) (ans *= Siz[i]) %= MOD;
}
if(cyc) return ans; int all = (1 << cntb) - 1;
rep(s, 1, all) cbit[s] = cbit[s&~(s&-s)] + 1, Log[s] = s == 1 ? 0 : Log[s>>1] + 1;
rep(s, 1, all) {
LL tmp;
int csiz = 0, tot;
if(cbit[s] == 1) {
csiz = Siz[Log[s]];
if(csiz < 3) continue;
tmp = (((LL)csiz * (csiz - 1) >> 1) % MOD + MOD - csiz + 1) % MOD;
}
else if(cbit[s] == 2) {
int t1 = s & -s, t2 = (s ^ t1) & -(s ^ t1);
t1 = Log[t1]; t2 = Log[t2];
if(Siz[t1] == 1 && Siz[t2] == 1) continue;
csiz = Siz[t1] + Siz[t2];
tmp = (LL)Siz[t1] * Siz[t2] % MOD;
tmp = (tmp * (tmp - 1) >> 1) % MOD;
}
else {
tmp = 617283946ll * fac[cbit[s]-1] % MOD;
rep(i, 0, cntb - 1) if(s >> i & 1)
csiz += Siz[i], (tmp *= (LL)Siz[i] * Siz[i] % MOD) %= MOD;
}
tot = cntb - cbit[s] + 1;
if(tot > 1) {
(tmp *= Pow(n, tot - 2) % MOD * csiz % MOD) %= MOD;
rep(i, 0, cntb - 1) if(!(s >> i & 1)) (tmp *= Siz[i]) %= MOD;
}
(ans += tmp) %= MOD;
} return ans;
}
};

[TC_SRM_460]TheCitiesAndRoadsDivOne的更多相关文章

  1. topcoder srm 460 div1

    problem1 link 设$f[i][j]$表示已经分配了answers中的前$i$个,分配给的问题的状态为 $j$的方案数. 其中状态可以用$n$位的三进制表示,0表示还未分配,1表示已分配是 ...

随机推荐

  1. CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第一节

    原文链接 第一节 CUDA 让你可以一边使用熟悉的编程概念,一边开发可在GPU上运行的软件. Rob Farber 是西北太平洋国家实验室(Pacific Northwest National Lab ...

  2. let和const在es6中的异同点

    let和const这两个都是声明一个变量或函数的方法与var差不太多的效果 let的声明在for循环中,当你定义的是多少,最后你的值就是多少开始的,它只进行一次循环,不会像var那样去一遍一遍的去遍历 ...

  3. [BZOJ] 2044: 三维导弹拦截

    排序去掉一维,剩下两维可以直接\(O(n^2)\)做,也可以用二维树状数组(但是不方便建边),解决第一问 第二问,按转移顺序连边,建出DAG,求最小不可重链覆盖即可 #include<algor ...

  4. 【Java_Spring】java解析多层嵌套json字符串

    java解析多层嵌套json字符串    

  5. 短信验证码js

    var isSmsSend = false; function clickButtona(obj){ var obj = $(obj); var mobile=$("input[name=m ...

  6. java util - 在java代码中执行javascript代码工具 rhino-1.7.7.jar

    需要 rhino-1.7.7.jar 包 代码示例: package cn.java.mozilla.javascript; import org.mozilla.javascript.Context ...

  7. LRU算法原理解析

    LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的. 现代操作系统提供了一种对主存的抽象概念虚拟内存,来对主存进行更好地管理.他将主存 ...

  8. 理解 Objective-c "属性"

    理解 Objective-c "属性" @property 是OC中能够快速定义一个属性的关键字,如下我们定义一个属性. @property NSString *String; 这 ...

  9. MySQL的增、删、查、改操作命令

    MySQL的增.删.查.改操作命令: 一.修改mysql数据库密码 格式:mysqladmin -u用户名 -p旧密码 password 新密码. 二.查看 查看多少个数据库:注意 后面带s #查看 ...

  10. f触发器、存储过程

    drop trigger trig_insert--删除触发器