码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3456]城市规划:多项式,分治

时间:2019-12-09 18:39:14      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:不同的   现在   col   最大   解决   block   去掉   时间   scanf   

Description

刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案. 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目. 由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.n<=130000

物理学考是想FFT的好时间。

首先,按照习惯FFT的题先当成dp做。

设$f_i$表示有i个点的联通图有几个。

然后我们发现它不能转移。

于是我们设$g_i$表示有i个点的不联通图有几个。

$f_i+g_i=2^{\frac{i \times (i-1)}{2}}$

就是联不联通的情况都加起来就是所有的图,总数量就是讨论每一条边建不建。

然后我们要考虑怎么转移不会重复。一个比较简单的想法是去掉不联通图中的联通块,但是这样会重复。

多yy几分钟。于是就想到之前的常用技巧:钦定。

我们钦定编号最大的点所在的联通块。每次只去除这个联通块。这样就不重复了。

$g_i=\sum\limits_{j=1}^{i-1} f_j \times (f_{i-j} + g_{i-j}) \times C_{i-1}^{j-1}$

含义就是:枚举i号点所在的联通块大小为j,这个联通块的总方案数是$f_j$,剩余部分随意反正它已经不联通了,是$f_{i-j}+g_{i-j}$

然后再在除了i号点以外的$i-1$个点中选定具体是哪$j-1$个点和点i在同一个联通块里,是$C_{i-1}^{j-1}$

然后发现转移是带有依赖的,于是用分治FFT解决。

技术图片
 1 #include<cstdio>
 2 #define int long long
 3 #define mod 1004535809
 4 #define S 131073
 5 int a[S],b[S],h[S],fac[S],inv[S],g[S],len,n,rev[S];
 6 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 7 int C(int b,int t){return fac[b]*inv[t]%mod*inv[b-t]%mod;}
 8 void NTT(int *a,int opt){
 9     for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0);
10     for(int i=0;i<len;++i)if(rev[i]>i)a[i]^=a[rev[i]]^=a[i]^=a[rev[i]];
11     for(int mid=1;mid<len;mid<<=1)
12         for(int i=0,t=pow(3,opt*(mod-1)/mid/2+mod-1);i<len;i+=mid<<1)
13             for(int j=0,w=1,x,y;j<mid;++j,w=w*t%mod)
14                 x=a[i+j],y=a[i+j+mid]*w%mod,a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod;
15     if(opt==-1)for(int i=0,iv=pow(len,mod-2);i<len;++i)a[i]=a[i]*iv%mod;
16 }
17 void solve(int l,int r){
18     if(l==r){g[l]=fac[l-1]*g[l]%mod;return;}
19     int mid=l+r>>1;solve(l,mid);
20     len=1;while(len<=r-l+1)len<<=1;
21     for(int i=0;i<len;++i)a[i]=b[i]=0;
22     for(int i=0;i<=r-l+1;++i)a[i]=h[i]*inv[i]%mod;
23     for(int i=l;i<=mid;++i)b[i-l]=(h[i]-g[i]+mod)*inv[i-1]%mod;
24     NTT(a,1);NTT(b,1);
25     for(int i=0;i<len;++i)a[i]=a[i]*b[i]%mod;
26     NTT(a,-1);
27     for(int i=mid+1;i<=r;++i)g[i]=(g[i]+a[i-l])%mod;
28     solve(mid+1,r);
29 }
30 signed main(){
31     scanf("%lld",&n);fac[0]=1;
32     for(int i=1;i<=n;++i)fac[i]=fac[i-1]*i%mod;
33     inv[n]=pow(fac[n],mod-2);
34     for(int i=n-1;~i;--i)inv[i]=inv[i+1]*(i+1)%mod;
35     for(int i=1;i<=n;++i)h[i]=pow(2,i*(i-1)/2);
36     solve(1,n);printf("%lld\n",(h[n]-g[n]+mod)%mod);
37 }
View Code

[bzoj3456]城市规划:多项式,分治

标签:不同的   现在   col   最大   解决   block   去掉   时间   scanf   

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12012535.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!