PS:THANKS FOR GJR——ssl_xxy
题目
求N个节点的无向连通图(节点有标号)
分析
可以发现,直接求太难求,像上一题Gerald and Giant Chess一样,必须反向求答案,then
f
[
i
]
=
2
i
∗
(
i
−
1
)
÷
2
−
∑
j
=
1
i
−
1
f
[
j
]
×
C
i
−
1
j
−
1
×
2
(
i
−
j
)
∗
(
i
−
j
−
1
)
÷
2
f[i]=2^{i*(i-1)\div2}-\sum_{j=1}^{i-1}f[j]\times C_{i-1}^{j-1}\times2^{(i-j)*(i-j-1)\div2}
f[i]=2i∗(i−1)÷2−j=1∑i−1f[j]×Ci−1j−1×2(i−j)∗(i−j−1)÷2
然后就是高精度了
代码
#include <cstdio>
#include <vector>
#define mod 10000
typedef unsigned long long ull;
std::vector<ull>tri[50]; std::vector<ull>c[50]; std::vector<ull>f[50];
void print(ull ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int min(int a,int b){return (a<b)?a:b;}
int main(){
for (register int i=0;i<50;i++) c[i].push_back(1);
for (register int i=0;i<50;i++)
for (register int j=1;j<=i+1>>1;j++) //只存一半
c[i].push_back(c[i][j-1]*(i-j+2)/j);//组合公式
tri[0].push_back(1);
for (register int i=1;i<50;i++){
tri[i]=tri[i-1]; ull g=0,s;
for (register int j=0;j<tri[i].size();j++){//高精乘单精,tri是2^高斯等差数列公式次方
s=tri[i][j]*(1ll<<i)+g;
g=s/mod; tri[i][j]=s%mod;
}
while (g) tri[i].push_back(g%mod),g/=mod;
}
f[0].push_back(1);
for (register int i=1;i<50;i++){
f[i]=tri[i];
for (register int j=0;j<i;j++){
std::vector<ull>t,t1; t=tri[i-j-1]; t1.clear(); ull g=0,s;
for (register int p=0;p<t.size();p++){
s=t[p]*c[i-1][min(j,i-j)]+g;
g=s/mod; t[p]=s%mod;
}
while (g) t.push_back(g%mod),g/=mod;
for (register int p1=0;p1<t.size();p1++)
for (register int p2=0;p2<f[j].size();p2++){//高精乘高精
if (t1.size()==p1+p2) t1.push_back(t[p1]*f[j][p2]); else t1[p1+p2]+=t[p1]*f[j][p2];
if (t1.size()==p1+p2+1) t1.push_back(t1[p1+p2]/mod); else t1[p1+p2+1]+=t1[p1+p2]/mod;
t1[p1+p2]%=mod;
}
g=0;
while (t1.size()<f[i].size()) t1.push_back(0);//一定要注意补0(vector)
for (register int p=0;p<f[i].size();p++)//高精减高精
if (f[i][p]>=t1[p]+g) f[i][p]-=t1[p]+g,g=0;
else f[i][p]+=mod-t1[p]-g,g=1;
}
}
int n;
while (scanf("%d",&n)==1&&n)
{
for (register int j=f[n-1].size()-1;j>=0;j--){
ull k=mod/10; if (j<f[n-1].size()-1)
while (k>f[n-1][j]&&k>1) putchar('0'),k/=10;
print(f[n-1][j]);
}
putchar('\n');
}
return 0;
}