bzoj3456 城市规划(分治NTT)
2018-02-04 09:09
399 查看
bzoj3456 城市规划
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3456题意:
阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案。
换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目。
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可。
数据范围
n <= 130000
题解:
令gigi为ii个点的图的数量,则gi=2n(n−1)2gi=2n(n−1)2,令fifi为ii个点的简单无向连通图数目,有:
fi=gi−∑j=1i−1fj∗(i−1j−1)∗gi−jfi=gi−∑j=1i−1fj∗(i−1j−1)∗gi−j
对于减掉的那个式子:
∑j=1i−1fj∗(i−1j−1)∗gi−j=∑j=1i−1(i−1)!(j−1)!(i−j)!∗fj∗gi−j=(i−1)!∑j=1i−1fj(j−1)!∗gi−j(i−j)!∑j=1i−1fj∗(i−1j−1)∗gi−j=∑j=1i−1(i−1)!(j−1)!(i−j)!∗fj∗gi−j=(i−1)!∑j=1i−1fj(j−1)!∗gi−j(i−j)!
若令Fi=fi(i−1)!Fi=fi(i−1)!,Gi=gi−j(i−j)!Gi=gi−j(i−j)!
则fi=gi−(i−1)!∑j=1i−1Fj∗Gi−jfi=gi−(i−1)!∑j=1i−1Fj∗Gi−j,如果让未算出的Fn=F0=0Fn=F0=0,且G0=0G0=0,减掉的就完全转化为了标准卷积形式,可以使用NTT了:
fi=gi−(i−1)!∑j=0iFj∗Gi−jfi=gi−(i−1)!∑j=0iFj∗Gi−j
由于计算出fifi需要用到f0...fi−1f0...fi−1,所以用分治NTT即可。
说起来好像很简单的样子,然而调题调一天…
第一个错误:wi没有赋初值为1。
第二个错误:预处理g数组时因为指数是LL乘爆了。发现这个问题是因为
44824这组数据过不去。
要注意的地方大概是分治时计算[lf,mid]的f对[mid+1,rg]的贡献时,要想清楚哪一位具体对应哪一位。因为lf需要加上(rg-lf)才等于rg,所以用于相乘的g数组是[1,rg-lf]。
代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define LL long long using namespace std; const int mod=1004535809;//479*2^21+1 g=3 const int N=600050; int G=3; int n,fac ,inv ,f ,a ,g ,b ,R ,iv ,w ,_w ; int modpow(int A,LL B) { int ret=1; int base=A; for(;B;B>>=1) { if(B&1) ret=(1LL*ret*base)%mod; base=(1LL*base*base)%mod; } return ret; } void NTT(int *x,int flag,int len) { for(int i=0;i<len;i++) if(i<R[i]) swap(x[i],x[R[i]]); for(int m=2;m<=len;m<<=1) { int l=m>>1; int wn,wi=1; if(flag==1) wn=w[m]; else wn=_w[m]; for(int j=0;j<len;j+=m) { wi=1; for(int i=0;i<l;i++) { int y=(1LL*wi*x[i+j+l])%mod; x[i+j+l]=(x[i+j]-y+mod)%mod; x[i+j]=(x[i+j]+y)%mod; wi=(1LL*wi*wn)%mod; } } } if(flag==-1) for(int i=0;i<len;i++) x[i]=(1LL*x[i]*iv[len])%mod; } void solve(int lf,int rg) { if(lf==rg) {f[lf]=(g[lf]-(1LL*f[lf]*fac[lf-1])%mod+mod)%mod; return;} int mid=(lf+rg)>>1; solve(lf,mid); int len=1,p=0; for(;len<2*(rg-lf+1);len<<=1,p++); R[0]=0; for(int i=1;i<len;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(p-1)); for(int i=0;i<=len;i++) a[i]=b[i]=0; for(int i=lf;i<=mid;i++) a[i-lf+1]=(1LL*f[i]*inv[i-1])%mod; for(int i=1;i<=rg-lf;i++) b[i]=(1LL*g[i]*inv[i])%mod; NTT(a,1,len); NTT(b,1,len); for(int i=0;i<len;i++) a[i]=(1LL*a[i]*b[i])%mod; NTT(a,-1,len); for(int i=mid+1;i<=rg;i++) f[i]=(f[i]+a[i-lf+1])%mod; solve(mid+1,rg); } int main() { scanf("%d",&n); inv[0]=fac[0]=inv[1]=fac[1]=1; for(int i=2;i<=4*n;i++) fac[i]=1LL*fac[i-1]*i%mod,inv[i]=modpow(fac[i],mod-2); g[0]=0; for(int i=1;i<=4*n;i++) g[i]=modpow(2,(1LL*i*(i-1)/2LL)); for(int i=1,p=0;i<=4*n;i<<=1,p++) {w[i]=modpow(G,(mod-1)/i),_w[i]=modpow(w[i],mod-2),iv[i]=modpow(i,mod-2);} solve(1,n); printf("%d\n",f ); return 0; }
相关文章推荐
- BZOJ3456 城市规划 【分治NTT】
- BZOJ3456:城市规划 (多项式求逆/分治+NTT)
- BZOJ 3456: 城市规划 多项式求逆/分治NTT
- 【XSY1332】【BZOJ3456】轩辕朗的城市规划 无向连通图计数 CDQ分治 FFT 多项式求逆 多项式ln
- Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)
- Bzoj3456:城市规划:NTT
- 【Tinsen】A1493. 城市规划【简单无向连通图个数——NTT】
- [bzoj3456]城市规划
- HDU 5322 NTT与分治
- HDU5322 Hope(DP + CDQ分治 + NTT)
- [BZOJ3456]城市规划
- BZOJ3456 城市规划 【多项式求ln】
- hdu 5279 YJC plays Minecraft 分治 NTT
- ZOJ 3874 Permutation Graph 分治NTT
- 【BZOJ3456】城市规划 多项式求逆
- HDU 5552 (CDQ分治 NTT)
- Bzoj3456 城市规划
- ZOJ3874 Permutation Graph(DP+分治NTT)
- [BZOJ3456]城市规划
- [bzoj3456] 城市规划 [递推+多项式求逆]