Description
刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
Input
Output
仅一行一个整数, 为方案数 mod 1004535809.
Sample Input
3
Sample Output
4
HINT
Source
方法一:cdq+ntt
设f[n]为n个点的答案,则
这就可以做了
code:
1 #include<cstdio>
2 #include<iostream>
3 #include<cmath>
4 #include<cstring>
5 #include<algorithm>
6 #define maxn 262148
7 #define mod 1004535809
8 #define g 3
9 using namespace std;
10 typedef long long int64;
11 char ch;
12 int n;
13 int a[maxn],b[maxn],c[maxn],Wn[2][maxn],wn,w,t1,t2;
14 int f[maxn],pow2[maxn],fac[maxn],inv_fac[maxn],inv_n[maxn];
15 int re[19][maxn];
16 bool ok;
17 inline void read(int &x){
18 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
19 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
20 if (ok) x=-x;
21 }
22 inline int rev(int len,int v){
23 int t=0;
24 for (int i=0;i<len;i++) t<<=1,t|=v&1,v>>=1;
25 return t;
26 }
27 inline int ksm(int a,int b){
28 int64 t=1;
29 for (;b;b>>=1){if (b&1) t=1LL*t*a%mod; a=1LL*a*a%mod;}
30 return t;
31 }
32 inline int ksm(int a,int64 b){
33 int64 t=1;
34 for (;b;b>>=1){if (b&1) t=1LL*t*a%mod; a=1LL*a*a%mod;}
35 return t;
36 }
37 inline void ntt(int *a,int n,int len,int op){
38 for (int i=0,t=re[len][i];i<n;i++,t=re[len][i]) if (i<t) swap(a[i],a[t]);
39 for (int s=2;s<=n;s<<=1){
40 wn=Wn[op][s];
41 for (int i=0;i<n;i+=s){
42 w=1;
43 for (int j=i;j<i+(s>>1);j++,w=1LL*w*wn%mod){
44 t1=a[j],t2=1LL*w*a[j+(s>>1)]%mod;
45 a[j]=(t1+t2)%mod,a[j+(s>>1)]=(t1-t2+mod)%mod;
46 }
47 }
48 }
49 if (op==1){
50 int x=inv_n[n];
51 for (int i=0;i<n;i++) a[i]=1LL*a[i]*x%mod;
52 }
53 }
54 inline void solve(int l,int r){
55 if (l==r){
56 f[l]=(pow2[l]-(int)(1LL*fac[l-1]*f[l]%mod)+mod)%mod;
57 return;
58 }
59 int m=(l+r)>>1;
60 solve(l,m);
61 int n=1,len=0;
62 while (n<((r-l+1)<<1)) n<<=1,len++;
63 for (int i=0;i<n;i++) a[i]=0;
64 for (int i=0;i<n;i++) b[i]=0;
65 for (int i=l;i<=m;i++) a[i-l]=1LL*f[i]*inv_fac[i-1]%mod;
66 for (int i=1;i<r-l+1;i++) b[i]=1LL*pow2[i]*inv_fac[i]%mod;
67 ntt(a,n,len,0),ntt(b,n,len,0);
68 for (int i=0;i<n;i++) c[i]=1LL*a[i]*b[i]%mod;
69 ntt(c,n,len,1);
70 for (int i=m+1;i<=r;i++) f[i]=(f[i]+c[i-l])%mod;
71 solve(m+1,r);
72 }
73 void init(){
74 read(n);
75 for (int i=1;i<=n;i++) pow2[i]=ksm(2,(1LL*i*(i-1))>>1);
76 fac[0]=1;
77 for (int i=1;i<=n;i++) fac[i]=1LL*i*fac[i-1]%mod;
78 for (int i=0;i<=n;i++) inv_fac[i]=ksm(fac[i],mod-2);
79 for (int i=2;i<(n<<2);i<<=1) Wn[0][i]=ksm(g,(mod-1)/i);
80 for (int i=2;i<(n<<2);i<<=1) Wn[1][i]=ksm(Wn[0][i],mod-2);
81 for (int i=2;i<(n<<2);i<<=1) inv_n[i]=ksm(i,mod-2);
82 for (int i=1;(1<<i)<(n<<2);i++){
83 for (int j=0;j<(1<<i);j++) re[i][j]=rev(i,j);
84 }
85 }
86 int main(){
87 init(),solve(1,n);
88 printf("%d\n",f[n]);
89 return 0;
90 }
方法二:多项式的逆元
http://blog.miskcoo.com/2015/05/bzoj-3456
如何求多项式的逆元http://blog.miskcoo.com/2015/05/polynomial-inverse
code:
1 #include<cstdio>
2 #include<iostream>
3 #include<cmath>
4 #include<cstring>
5 #include<algorithm>
6 #define maxn 262148
7 #define mod 1004535809
8 #define g 3
9 using namespace std;
10 typedef long long int64;
11 char ch;
12 int m,n,len,N;
13 int a[maxn],b[maxn],c[maxn],f[maxn],t[maxn],Wn[2][maxn],wn,w,t1,t2;
14 int pow2[maxn],fac[maxn],inv_fac[maxn],inv_n[maxn];
15 int re[19][maxn];
16 bool ok;
17 inline void read(int &x){
18 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
19 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
20 if (ok) x=-x;
21 }
22 inline int rev(int len,int v){
23 int t=0;
24 for (int i=0;i<len;i++) t<<=1,t|=v&1,v>>=1;
25 return t;
26 }
27 inline int ksm(int a,int b){
28 int64 t=1;
29 for (;b;b>>=1){if (b&1) t=1LL*t*a%mod; a=1LL*a*a%mod;}
30 return t;
31 }
32 inline int ksm(int a,int64 b){
33 int64 t=1;
34 for (;b;b>>=1){if (b&1) t=1LL*t*a%mod; a=1LL*a*a%mod;}
35 return t;
36 }
37 inline void ntt(int *a,int n,int len,int op){
38 for (int i=0,t=re[len][i];i<n;i++,t=re[len][i]) if (i<t) swap(a[i],a[t]);
39 for (int s=2;s<=n;s<<=1){
40 wn=Wn[op][s];
41 for (int i=0;i<n;i+=s){
42 w=1;
43 for (int j=i;j<i+(s>>1);j++,w=1LL*w*wn%mod){
44 t1=a[j],t2=1LL*w*a[j+(s>>1)]%mod;
45 a[j]=(t1+t2)%mod,a[j+(s>>1)]=(t1-t2+mod)%mod;
46 }
47 }
48 }
49 if (op==1){
50 int x=inv_n[n];
51 for (int i=0;i<n;i++) a[i]=1LL*a[i]*x%mod;
52 }
53 }
54 void init(){
55 read(m),n=m+1,N=1;
56 while (N<(n<<1)) N<<=1,len++;
57 for (int i=0;i<=n;i++) pow2[i]=ksm(2,(1LL*i*(i-1))>>1);
58 fac[0]=1;
59 for (int i=1;i<=n;i++) fac[i]=1LL*i*fac[i-1]%mod;
60 for (int i=0;i<=n;i++) inv_fac[i]=ksm(fac[i],mod-2);
61 for (int i=2;i<(n<<2);i<<=1) Wn[0][i]=ksm(g,(mod-1)/i);
62 for (int i=2;i<(n<<2);i<<=1) Wn[1][i]=ksm(Wn[0][i],mod-2);
63 for (int i=2;i<(n<<2);i<<=1) inv_n[i]=ksm(i,mod-2);
64 for (int i=1;(1<<i)<(n<<2);i++) for (int j=0;j<(1<<i);j++) re[i][j]=rev(i,j);
65 for (int i=0;i<=m;i++) a[i]=1LL*pow2[i]*inv_fac[i]%mod;
66 for (int i=1;i<=m;i++) c[i]=1LL*pow2[i]*inv_fac[i-1]%mod;
67 }
68 void get_inv(int deg,int *a,int *b){
69 if (deg==1){b[0]=ksm(a[0],mod-2);return;}
70 get_inv((deg+1)>>1,a,b);
71 int n=1,len=0;
72 while (n<(deg<<1)) n<<=1,len++;
73 for (int i=0;i<deg;i++) t[i]=a[i];
74 for (int i=deg;i<n;i++) t[i]=0;
75 ntt(t,n,len,0),ntt(b,n,len,0);
76 for (int i=0;i<n;i++) b[i]=(2LL-1LL*t[i]*b[i]%mod+mod)*b[i]%mod;
77 ntt(b,n,len,1);
78 for (int i=deg;i<n;i++) b[i]=0;
79 }
80 int main(){
81 init();
82 get_inv(n,a,b);
83 ntt(b,N,len,0),ntt(c,N,len,0);
84 for (int i=0;i<N;i++) f[i]=1LL*b[i]*c[i]%mod;
85 ntt(f,N,len,1);
86 printf("%d\n",(int)(1LL*f[m]*fac[m-1]%mod));
87 return 0;
88 }