题目链接:

http://poj.org/problem?id=1737

题意:

求 \(n\) 个点的无向简单(无重边无自环)连通图的个数。\((n<=50)\)

题解:

这题你甚至能OEIS。

http://oeis.org/A001187

但不支持这样做。TAT

间接做。

总方案数减去不合法方案。

因为\(n\)个点的完全图有 \(C(n,2)={n(n-1) \over 2}\) 条边,显然就有 \(2^{C(n,2)}\) 种子图,即枚举每条边是否选择。

设$ f[i]$ 表示每个点都和点 \(1\) 相连的连通图的个数 。

假设\(1\) 号点所在的连通块大小为 \(i\)。那么和 \(1\) 连通的这 \(i−1\) 个点就有 \(C(n-1,i-1)\) ,方案数则为:\(C(n-1,i-1)*f[i]\)。

然后其它 \(n−i\) 个点间任意连边即可,这时方案数为 \(2^{C(n-i,2)}\)。

综上,则存在递推式:

$$f[n]=2{C(n,2)}-\sum_{i=1}{n-1}f[i]C(n-1,i-1)2^{C(n-i,2)}$$

答案就是\(f[n]\)。

然后就套个大数板子。额...过世OJ好像不支持c++11。懒得改了,虽然不过,但代码是正确的。QAQ

代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <complex>
#include <cstring>
#include <stdlib.h>
#include <string.h>
using namespace std;
typedef long long LL;
const double PI = acos(-1);
void rader(vector<complex<double> >& y) {
int len = y.size();
int i, j, k;
for (i = 1, j = len / 2; i < len - 1; i++) {
if (i < j) swap(y[i], y[j]);
k = len / 2;
while (j >= k) {
j -= k;
k /= 2;
}
if (j < k) j += k;
}
}
void fft(vector<complex<double> >& y, int on) {
int len = y.size();
rader(y);
for (int h = 2; h <= len; h <<= 1) {
complex<double> wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h));
for (int j = 0; j < len; j += h) {
complex<double> w(1, 0);
for (int k = j; k < j + h / 2; k++) {
complex<double> u = y[k];
complex<double> t = w * y[k + h / 2];
y[k] = u + t;
y[k + h / 2] = u - t;
w = w * wn;
}
}
}
if (on == -1) for (auto& i : y) i.real(i.real() / len);
}
class BigInt {
private:
string num;
string sign; public:
const string to_string() const {
if (this->sign == "-") return this->sign + this->num;
else return this->num;
}
const LL toll() { return stoll(this->to_string()); }
const int toi() { return stoi(this->to_string()); }
BigInt() : num("0"), sign("+") {}
BigInt(const int t) {
if (t < 0) {
this->num = std::to_string(-t);
this->sign = "-";
} else {
this->num = std::to_string(t);
this->sign = "+";
}
}
BigInt(const LL t) {
if (t < 0) {
this->num = std::to_string(-t);
this->sign = "-";
} else {
this->num = std::to_string(t);
this->sign = "+";
}
}
BigInt(const string& t) {
if (t[0] == '-') {
this->num = t.substr(1);
this->sign = "-";
} else {
this->num = t;
this->sign = "+";
}
int flag = 0;
while (flag < (int)this->num.length() - 1 && this->num[flag] == '0') flag++;
this->num = this->num.substr(flag);
}
BigInt(char* const t) : BigInt(string(t)) {}
friend bool operator< (const BigInt& t, const BigInt& s) {
if (t.sign != s.sign) {
if (t.sign == "-") return true;
else return false;
} else {
if (t.sign == "-") {
if (t.num.length() == s.num.length()) {
return t.num > s.num;
} else {
return t.num.length() > s.num.length();
}
} else {
if (t.num.length() == s.num.length()) {
return t.num < s.num;
} else {
return t.num.length() < s.num.length();
}
}
}
}
friend bool operator> (const BigInt& t, const BigInt& s) {
return s < t;
}
friend bool operator== (const BigInt& t, const BigInt& s) {
return t.num == s.num && t.sign == s.sign;
}
friend bool operator!= (const BigInt& t, const BigInt& s) {
return !(t == s);
}
friend bool operator<= (const BigInt& t, const BigInt& s) {
return t == s || t < s;
}
friend bool operator>= (const BigInt& t, const BigInt& s) {
return t == s || t > s;
}
friend const BigInt abs(const BigInt& t) {
BigInt ans = t;
if (ans.sign == "-") ans.sign = "+";
return ans;
}
friend const BigInt operator- (const BigInt& t) {
BigInt ans = t;
if (ans.sign == "-") ans.sign = "+";
else ans.sign = "-";
return ans;
}
friend istream& operator>> (istream& in, BigInt& t) {
string s;
in >> s;
t = s;
return in;
}
friend ostream& operator<< (ostream& out, const BigInt& t) {
out << t.to_string();
return out;
}
friend const BigInt operator+ (const BigInt& t, const BigInt& s) {
BigInt ans, sub;
if (t.num.length() < s.num.length()) {
ans = s;
sub = t;
} else if (t.num.length() == s.num.length()) {
if (t.num < s.num) {
ans = s;
sub = t;
} else {
ans = t;
sub = s;
}
} else {
ans = t;
sub = s;
}
int sub_l = sub.num.length();
int ans_l = ans.num.length();
if (t.sign == s.sign) {
for (int i = 1; i <= sub_l; i++) {
ans.num[ans_l - i] += sub.num[sub_l - i] - '0';
}
int flag = 0;
for (int i = 1; i <= ans_l; i++) {
if (ans.num[ans_l - i] > '9') {
ans.num[ans_l - i] -= 10;
if (i == ans_l) {
flag = 1;
} else {
ans.num[ans_l - i - 1] += 1;
}
} else if (i >= sub_l) {
break;
}
}
if (flag) ans.num = "1" + ans.num;
} else {
for (int i = 1; i <= sub_l; i++) {
ans.num[ans_l - i] -= sub.num[sub_l - i] - '0';
}
for (int i = 1; i <= ans_l; i++) {
if (ans.num[ans_l - i] < '0') {
ans.num[ans_l - i] += 10;
ans.num[ans_l - i - 1] -= 1;
} else if (i >= sub_l) {
break;
}
}
int flag = 0;
while (flag < ans_l - 1 && ans.num[flag] == '0') flag++;
ans.num = ans.num.substr(flag);
if (ans.num == "0") ans.sign = "+";
}
return ans;
}
friend const BigInt operator- (const BigInt& t, const BigInt& s) {
BigInt sub = s;
if (sub.sign == "+") sub.sign = "-";
else sub.sign = "+";
return t + sub;
}
friend const BigInt operator* (const BigInt& t, const BigInt& s) {
BigInt res;
if (s.sign == t.sign) res.sign = "+";
else res.sign = "-";
vector<complex<double> > x1, x2;
vector<int> sum;
string str1 = t.num, str2 = s.num;
int len1 = str1.length();
int len2 = str2.length();
int len = 1;
while (len < len1 * 2 || len < len2 * 2) len <<= 1;
for (int i = 0; i < len1; i++) {
x1.push_back(complex<double>(str1[len1 - 1 - i] - '0', 0));
}
for (int i = len1; i < len; i++) {
x1.push_back(complex<double>(0, 0));
}
for (int i = 0; i < len2; i++) {
x2.push_back(complex<double>(str2[len2 - 1 -i] - '0', 0));
}
for (int i = len2; i < len; i++) {
x2.push_back(complex<double>(0, 0));
}
fft(x1, 1);
fft(x2, 1);
for (int i = 0; i < len; i++) x1[i] = x1[i] * x2[i];
fft(x1, -1);
for (auto& i : x1) sum.push_back((int)(i.real() + 0.5));
for (int i = 0; i < len; i++) {
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
len = len1 + len2 - 1;
while (sum[len] <= 0 && len > 0) len--;
res.num = "";
for (int i = len; i >= 0; i--) res.num += sum[i] + '0';
if (res.num == "0") res.sign = "+";
return res;
}
friend const BigInt operator/ (const BigInt& t, const BigInt& s) {
if (s == 0) throw;
BigInt res;
if (s.sign == t.sign) res.sign = "+";
else res.sign = "-";
BigInt sub = abs(t), ans = abs(s);
int w = sub.num.length() - ans.num.length();
for (int i = 0; i < w; i++) ans.num += "0";
while (w >= 0) {
int d = 0;
while (ans <= sub) {
sub -= ans;
d++;
}
res.num += d + '0';
ans.num = ans.num.substr(0, ans.num.length() - 1);
w--;
}
int flag = 0;
while (flag < (int)res.num.length() - 1 && res.num[flag] == '0') flag++;
res.num = res.num.substr(flag);
if (res.num == "0") res.sign = "+";
return res;
}
friend const BigInt operator% (const BigInt& t, const BigInt& s) {
if (s == 0) throw;
BigInt sub = abs(t), ans = abs(s);
int w = sub.num.length() - ans.num.length();
for (int i = 0; i < w; i++) ans.num += "0";
while (w >= 0) {
int d = 0;
while (ans <= sub) {
sub -= ans;
d++;
}
w--;
ans.num = ans.num.substr(0, ans.num.length() - 1);
}
sub.sign = t.sign;
if (sub.num == "0") sub.sign = "+";
return sub;
}
friend BigInt& operator+= (BigInt& t, const BigInt& s) {
return t = t + s;
}
friend BigInt& operator-= (BigInt& t, const BigInt& s) {
return t = t - s;
}
friend BigInt& operator*= (BigInt& t, const BigInt& s) {
return t = t * s;
}
friend BigInt& operator/= (BigInt& t, const BigInt& s) {
return t = t / s;
}
friend BigInt& operator%= (BigInt& t, const BigInt& s) {
return t = t % s;
}
const BigInt subnum(int r, int l) {
BigInt ans = this->num.substr(this->num.length() - l, l - r);
ans.sign = this->sign;
return ans;
}
const BigInt subnum(int l) {
return this->subnum(0, l);
}
};
BigInt dp[110][110];
void init()
{
dp[0][0] = 1;
for(int i = 1; i <= 51; i++) {
dp[i][0] = 1;
for(int j = 1; j <= i; j++) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
}
}
}
BigInt expo[2000];
BigInt f[52];
int main(int argc, char const *argv[]) {
init();
int n;
expo[0] = 1;
for(long long i = 1; i <= 1250; i++) {
expo[i] = 2LL * expo[i - 1];
}
f[1] = 1;
f[2] = 1;
while(std::cin >> n) {
if(n == 0) break;
if(n <= 2) {
std::cout << "1" << '\n';
continue;
}
BigInt tmp = 0;
for(int i = 3; i <= n; i++) {
BigInt tot = expo[(i * (i - 1) >> 1)];
// std::cout << "tot = " << tot << '\n';
for(int j = 1; j <= i - 1; j++) {
tot = tot - f[j] * dp[i - 1][j - 1] * expo[((i - j) * ((i - j) - 1)) >> 1];
}
f[i] = tot;
}
std::cout << f[n] << '\n';
}
return 0;
}

POJ 1737 Connected Graph (大数+递推)的更多相关文章

  1. poj 1737 Connected Graph

    // poj 1737 Connected Graph // // 题目大意: // // 带标号的连通分量计数 // // 解题思路: // // 设f(n)为连通图的数量,g(n)为非连通图的数量 ...

  2. POJ 1737 Connected Graph 题解(未完成)

    Connected Graph Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3156   Accepted: 1533 D ...

  3. POJ 1737 Connected Graph(高精度+DP递推)

    题面 \(solution:\) 首先做个推销:带负数的压位高精度(加减乘+读写) 然后:由 \(N\) 个节点组成的无向图的总数为: \(2^{N*(N-1)/2}\) (也就是说这个图总共有 \( ...

  4. poj 3744 Scout YYF I(递推求期望)

    poj 3744 Scout YYF I(递推求期望) 题链 题意:给出n个坑,一个人可能以p的概率一步一步地走,或者以1-p的概率跳过前面一步,问这个人安全通过的概率 解法: 递推式: 对于每个坑, ...

  5. HDU-1041-Computer Transformation,大数递推,水过~~

                                                                                  Computer Transformatio ...

  6. POJ 1664 放苹果 (递推思想)

    原题链接:http://poj.org/problem?id=1664 思路:苹果m个,盘子n个.假设 f ( m , n ) 代表 m 个苹果,n个盘子有 f ( m , n ) 种放法. 根据 n ...

  7. 【POJ】2229 Sumsets(递推)

    Sumsets Time Limit: 2000MS   Memory Limit: 200000K Total Submissions: 20315   Accepted: 7930 Descrip ...

  8. POJ 3734 Blocks (线性递推)

    定义ai表示红色和绿色方块中方块数为偶数的颜色有i个,i = 0,1,2. aij表示刷到第j个方块时的方案数,这是一个线性递推关系. 可以构造递推矩阵A,用矩阵快速幂求解. /*********** ...

  9. POJ 3046 Ant Counting(递推,和号优化)

    计数类的问题,要求不重复,把每种物品单独考虑. 将和号递推可以把转移优化O(1). f[i = 第i种物品][j = 总数量为j] = 方案数 f[i][j] = sigma{f[i-1][j-k], ...

随机推荐

  1. POJ——T 3255 Roadblocks|| COGS——T 315. [POJ3255] 地砖RoadBlocks || 洛谷—— P2865 [USACO06NOV]路障Roadblocks

    http://poj.org/problem?id=3255 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15680   ...

  2. [Recompose] Refactor React Render Props to Streaming Props with RxJS and Recompose

    This lesson takes the concept of render props and migrates it over to streaming props by keeping the ...

  3. Gonet2 游戏server框架解析之gRPC提高(5)

    上一篇blog是关于gRPC框架的基本使用,假设说gRPC仅仅是远程发几个參数,那和一个普通的http请求也没多大区别了. 所以今天我就来学习一下gRPC高级一点的用法. 流! 流能够依据用法,分为单 ...

  4. oracle_序列、索引、同义词

     ①序列 1.序列: 可供多个用户用来产生唯一数值的数据库对象     自己主动提供唯一的数值     共享对象     主要用于提供主键值     将序列值装入内存能够提高訪问效率 2.CREA ...

  5. Java中Socket上的Read操作堵塞问题

    从Socket上读取对端发过来的数据一般有两种方法: 1)依照字节流读取 BufferedInputStream in = new BufferedInputStream(socket.getInpu ...

  6. 消息推送学习一、原生Socket的使用

    消息推送也是客户端和服务器连接然后进行交互的一种形式,但是不同于HTTP的连接,这种连接需要长时间的进行,当有消息时可以及时推送到客户端.除此之外还有多个用户,可能需要针对其身份进行不同的推送等等要求 ...

  7. Installation from source on Windows 7 with Visual C++2012

    在这部分说明里,你将会学习到在配备有Visual C++的Windows平台下从源码安装ViSP.下面的这些安装步骤已经在32位Windows系统,CMake3.1和Visual Studio 201 ...

  8. RAID信息存放位置!

    今天偶然的机会,客户打电话说有一台DELL T110的服务器换了主板电池RAID信息没了进不去系统了,问我怎么处理,T110的RAID是主板集成的S100的RAID卡(算是软RAID,通过BIOS配置 ...

  9. dos 实用命令搜集

    dos 命令: 1.netstat -an 2.XP下打开凭证管理:  control keymgr.dll 3.刷新DHCP协议,重新自动获取IP *   ipconfig/release 命令来丢 ...

  10. JS中部分 Array 对象方法介绍

    1.concat() concat() 方法用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本 <script type="text/javascrip ...