题面



$ solution: $

首先做个推销:带负数的压位高精度(加减乘+读写)

然后:由 $ N $ 个节点组成的无向图的总数为: $ 2^{N\times (N-1)/2} $ (也就是说这个图总共有 $ N\times (N-1)/2 $ 条边,每一条边选或不选就可以得出来)

然后我们直接开始分析题目,因为这道题需要求无向连通图的方案数,这道题似乎也不是一个结论题, $ wch $ 决定去找找规律,是不是 $ n $ 和 $ n-1 $ 有什么关系,但是 $ wch $ 发现他打不出表。 然后 $ wch $ 想到了分治合并,但如果将它分为两份 $ \frac{n}{2} $ 似乎更不好合并了。但是他依旧觉得这题肯定可以用分开合并的方法(于是他觉得应该直接DP)。(说白了就是他比较傻,现在才想到直接DP)。

然后他试图写出转移方程,然后他懵了。他发现很难不重不漏的把所有情况算进去(两个联通图暴力连边会导致重复),但是他发现如果两个联通图中间不连边就可以组成一个不连通图,于是他恍然大悟:似乎可以用所有图的方案数减去不连通的方案数!而一个不连通图一定有若干个连通图组成,我们可以围绕一个连通图来数方案,于是一个转移应运而生:我们钦定有 $ k $ 个节点在左边某个联通图里(可以用组合数选 $ k $ 个),剩下的 $ i-k $ 个节点在右边的图里,但是这样仔细一想也会重复。为什么呢?我们围绕的那个 $ k $ 个节点组成的连通图是不确定的,他有可能被后面的枚举中( $ i-k $ 所组成的图)取到。所以我们要把它固定下来,(在算法竞赛里称为找基准点,并围绕它构造一个不可划分的整体)于是我们钦定一号节点在左边那个连通图中,这样我们就能不重不漏的算下左右情况了!

设 $ F[i] $ 表示有 $ i $ 个节点组成的联通图的个数有多少个,我们考虑这个怎么转移过来的:首先枚举左边的连通图的大小 $ 1<k<i $ ,然后我们要钦定一号结点在里面,所以我们只需要从剩下的 $ i-1 $ 个 节点里选出 $ k-1 $ 个即可(显然可以选 $ C^{k-1}_{i-1} $ 种),然后这 $ k $ 个节点是需要组成一个连通图的,所以再乘上一个 $ F[k] $ 然后我们还需要乘上后面的 $ i-k $ 个节点组成的任意图即: $ 2^{(i-k)\times (i-k-1)/2} $ 于是转移方程即为:

$ F[i]=2^{i\times (i-1)/2}-\sum{i-1}_{k=1}{C{k-1}_{i-1}\times F[k]\times 2^{(i-k)\times (i-k-1)/2}} $



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int using namespace std; int n; struct gj{ bool fu; //是否是负数
int tt,mod; //高精的长度
int s[1005]; //压位用的数组 inline gj(){ //整体初始化
fu=0; tt=0; mod=1e9;
memset(s,0,sizeof(s));
} inline gj read(){ register char ch; //高精度读入
while(!isdigit(ch=getchar()))if(ch=='-')fu=1;
char _[100005]; rg l=0,r=-1; _[0]=ch;
while(isdigit(_[++l]=getchar()));; tt=l/9-!(l%9);
for(rg i=(l-1)%9+1;i;--i) (s[tt]*=10)+=_[++r]^48;
for(rg i=tt-1;i>=0;--i)for(rg j=0;j<9;++j)(s[i]*=10)+=(_[++r]^48);
while(tt&&!s[tt])--tt;; return (*this);
}
inline void print(){ //高精度输出
if(fu)putchar('-');
printf("%d",s[tt]);
for(rg i=tt-1;i>=0;--i)
printf("%09d",s[i]);
putchar('\n');
} inline bool operator >(const gj &x){ //定义大于
if(tt!=x.tt)return tt>x.tt;
for(rg i=tt;i>=0;--i)
if(s[i]!=x.s[i])return s[i]>x.s[i];
return 0;
}
inline bool operator <(const gj &x){ //定义小于
if(tt!=x.tt)return tt<x.tt;
for(rg i=tt;i>=0;--i)
if(s[i]!=x.s[i])return s[i]<x.s[i];
return 0;
} inline gj operator =(int x){ //int的等于
while(tt)s[tt]=0,--tt;
s[0]=x%mod; s[1]=x/mod;
if(s[1])tt=1;; return *this;
}
inline gj operator =(ll x){ //int的等于
while(tt)s[tt]=0,--tt;
while(x)s[tt]=x%mod,x/=mod,++tt;
if(!s[tt])--tt;; return *this;
} inline void add(const gj &x){ //加法的底层
rg sign=0; if(x.tt>tt)tt=x.tt;
for(rg i=0;i<=tt;++i){
s[i]+=x.s[i]+sign; sign=0;
if(s[i]>mod)s[i]-=mod,sign=1;
}if(sign)s[++tt]=1;
} inline void cut(const gj &x){ //减法的底层
if(fu)cout<<54564<<endl;
rg sign=0;
for(rg i=0;i<=tt;++i){
s[i]-=x.s[i]+sign; sign=0;
if(s[i]<0)s[i]+=mod,sign=1;
}while(tt&&!s[tt])--tt;
if(!tt&&!s[tt]) fu=0;
} inline void mul(const gj &x){ //乘法的底层
gj y; ll num; y.tt=tt+x.tt;
for(rg i=0;i<=tt;++i){ num=0;
for(rg j=0;j<=x.tt;++j){
num=(ll)s[i]*x.s[j]+y.s[j+i]+num;
y.s[j+i]=num%mod; num/=mod;
} if(num)y.s[x.tt+i+1]=num;
}if(num)++y.tt;; *this=y;
} inline void operator +=(gj x){ //赋值加法重载
if(fu==x.fu){(*this).add(x); return;}
if(*this>x) (*this).cut(x);
else x.cut(*this),*this=x,fu^=1;
}
inline gj operator +(const gj &x){ //加法正常重载
gj y=*this; y+=x; return y;
} inline void operator -=(gj x){ //赋值减法重载
if(fu!=x.fu){(*this).add(x); return;}
if(*this>x){(*this).cut(x); return;}
x.cut(*this); *this=x; if(s[tt])fu^=1;
}
inline gj operator -(const gj &x){ //减法正常重载
gj y=*this; y-=x; return y;
} inline void operator *=(gj x){ //赋值乘法重载
if(!s[tt]||!x.s[x.tt]){gj y; *this=y;}
if(fu!=x.fu)fu=1;else fu=0;; (*this).mul(x);
}
inline gj operator *(const gj &x){ //乘法正常重载
gj y=*this; y*=x; return y;
} inline gj operator *(int x){ gj y; y=x; return (*this)*y;}
inline void operator *=(int x){gj y; y=x; (*this)*=y;}
inline gj operator +(int x){ gj y; y=x; return (*this)+y;}
inline void operator +=(int x){gj y; y=x; (*this)+=y;}
inline gj operator -(int x){ gj y; y=x; return (*this)-y;}
inline void operator -=(int x){gj y; y=x; (*this)-=y;}
}f[51],pf[1235],c[51][51]; inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
return sign?-res:res;
} int main(){
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
pf[0]=1; n=50;
for(rg i=0;i<=50;++i) c[i][0]=1;
for(rg i=0;i<=1225;++i) pf[i+1]=pf[i]*2;
for(rg i=1;i<=50;++i)
for(rg j=1;j<=50;++j)
c[i][j]=c[i-1][j]+c[i-1][j-1];
f[1]=1; f[2]=1;
for(rg i=3;i<=n;++i){
f[i]=pf[i*(i-1)/2];
for(rg j=1;j<i;++j)
f[i]-=f[j]*c[i-1][j-1]*pf[(i-j)*(i-j-1)/2];
} while((n=qr()))f[n].print();
return 0;
}

POJ 1737 Connected Graph(高精度+DP递推)的更多相关文章

  1. poj 1737 Connected Graph

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

  2. POJ 1737 Connected Graph (大数+递推)

    题目链接: http://poj.org/problem?id=1737 题意: 求 \(n\) 个点的无向简单(无重边无自环)连通图的个数.\((n<=50)\) 题解: 这题你甚至能OEIS ...

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

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

  4. hdu2089(数位DP 递推形式)

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. HOJ 2148&POJ 2680(DP递推,加大数运算)

    Computer Transformation Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4561 Accepted: 17 ...

  6. POJ 2229 sumset ( 完全背包 || 规律递推DP )

    题意 : 给出一个数 n ,问如果使用 2 的幂的和来组成这个数 n 有多少种不同的方案? 分析 :  完全背包解法 将问题抽象==>有重量分别为 2^0.2^1.2^2…2^k 的物品且每种物 ...

  7. hdu 2604 Queuing(dp递推)

    昨晚搞的第二道矩阵快速幂,一开始我还想直接套个矩阵上去(原谅哥模板题做多了),后来看清楚题意后觉得有点像之前做的数位dp的水题,于是就用数位dp的方法去分析,推了好一会总算推出它的递推关系式了(还是菜 ...

  8. Power oj2498/DP/递推

    power oj 2498 /递推 2498: 新年礼物 Time Limit: 1000 MS Memory Limit: 65536 KBTotal Submit: 12 Accepted: 3  ...

  9. BZOJ4321queue2——DP/递推

    题目描述 n 个沙茶,被编号 1~n.排完队之后,每个沙茶希望,自己的相邻的两 人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行:  现在想知道,存在多少方案满足沙茶们如此不苛刻的条件. ...

随机推荐

  1. 【Luogu】P1393动态逆序对(树套树)

    题目链接 树套树. 每次删掉x的时候会减去1到x-1里比x位置的数大的数和它构成的逆序对,以及x+1到n里比x位置的数小的数和它构成的逆序对. 顺带一提我发现平衡树insert的时候不是要splay一 ...

  2. BZOJ2281 [SDOI2011]黑白棋 【dp + 组合数】

    题目 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小A可以移动白色棋子 ...

  3. ado:SqlDataAdapter的两种不同写法,以及SqlCommand的两种不同写法

    原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] SqlDataAdapter:(它是自动打开连接且自动关闭的,所以可以不必显示打开关闭连接) SqlConnect ...

  4. Ajax 实现文件的下载

    JQuery的ajax函数的返回类型只有xml.text.json.html等类型,没有“流”类型,所以我们要实现ajax下载,不能够使用相应的ajax函数进行文件下载.但可以用js生成一个form, ...

  5. (7)C#连DB2---oledb方式

    1安装客户端 安装DbVisualizer Free 客户端软件 2编目 用 win+r  输入 db2cmd 启动命令行 要远程操作数据库,首先要进行编目,分三个步骤: 1. 在客户端建立服务器端数 ...

  6. luogu P1149 火柴棒等式

    题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 加号与等号各自 ...

  7. luogu P2296 寻找道路

    题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条 ...

  8. CAS 跨域原理

    http://www.blogjava.net/rain1102/articles/227739.html CAS(Central Authentication Service) 是 Yale 大学发 ...

  9. android开发教程之使用线程实现视图平滑滚动示例

    最近一直想做下拉刷新的效果,琢磨了好久,才走到通过onTouch方法把整个视图往下拉的步骤,接下来就是能拉下来,松开手要能滑回去啊.网上看了好久,没有找到详细的下拉刷新的例子,只有自己慢慢琢磨了.昨天 ...

  10. Donser Online Judge 完成运行使命~

    复试成功完成~ 2018年网研机考难度不大,仍然有些遗憾,前两题水题后两个题纯暴力 排行榜 排名 用户 题数 罚时 A B C D retest2018_INT246 (INT246) (+) (+) ...