BZOJ 3456 城市规划 快速傅里叶变换

题目大意:求n个点的无向简单连通图个数,n≤1.3?105

递推式:fi=2C2i?∑i?1j=1fj?Cj?1i?1?2C2i?j

推导戳这里

然后两侧同除(i?1)!得到:

fi(i?1)!=2C2i(i?1)!?∑i?1j=1fj?2C2i?j(j?1)!?(i?j)!

∑ij=1fj?2C2i?j(j?1)!?(i?j)!=2C2i(i?1)!

∑ij=1fj(j?1)!?2C2i?j(i?j)!=2C2i(i?1)!

这显然是一个卷积的形式

然后我们令:

A=∑ni=1fi(i?1)!xi

B=∑ni=02C2ii!xi

C=∑ni=12C2i(i?1)!xi

那么有A?B=C

然后有A≡C?B?1(mod xn+1)

多项式求逆搞一搞就好了

没想到还真有人的FFT比我还慢2333

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 263000
#define MOD 1004535809
#define G 3
using namespace std;
int n,m;
long long Quick_Power(long long x,long long y)
{
    long long re=1;
    while(y)
    {
        if(y&1) (re*=x)%=MOD;
        (x*=x)%=MOD; y>>=1;
    }
    return re;
}
void FFT(int a[],int n,int type)
{
    static int temp[M];
    int i;
    if(n==1) return ;
    for(i=0;i<n;i+=2)
        temp[i>>1]=a[i],temp[i+n>>1]=a[i+1];
    memcpy(a,temp,sizeof(a[0])*n);
    int *l=a,*r=a+(n>>1);
    FFT(l,n>>1,type);FFT(r,n>>1,type);
    long long w=Quick_Power(G,(long long)(MOD-1)/n*type%(MOD-1)),wn=1;
    for(i=0;i<n>>1;i++,(wn*=w)%=MOD)
        temp[i]=(l[i]+wn*r[i])%MOD,temp[i+(n>>1)]=(l[i]-wn*r[i]%MOD+MOD)%MOD;
    memcpy(a,temp,sizeof(a[0])*n);
}
void Get_Inv(int a[],int b[],int n)
{
    static int temp[M];
    int i;
    if(n==1)
    {
        b[0]=Quick_Power(a[0],MOD-2);
        return ;
    }
    Get_Inv(a,b,n>>1);
    memcpy(temp,a,sizeof(a[0])*n);
    memset(temp+n,0,sizeof(a[0])*n);
    FFT(temp,n<<1,1);
    FFT(b,n<<1,1);
    for(i=0;i<n<<1;i++)
        temp[i]=(long long)b[i]*(2-(long long)temp[i]*b[i]%MOD+MOD)%MOD;
    FFT(temp,n<<1,MOD-2);
    long long inv=Quick_Power(n<<1,MOD-2);
    for(i=0;i<n;i++)
        b[i]=temp[i]*inv%MOD;
    memset(b+n,0,sizeof(a[0])*n);
}
int main()
{
    static long long fac[M];
    static int A[M],B[M],C[M],inv_B[M];
    int i;
    cin>>n;
    for(m=1;m<=n;m<<=1);
    for(fac[0]=1,i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%MOD;
    for(i=0;i<=n;i++)
        B[i]=Quick_Power(2,((long long)i*(i-1)>>1)%(MOD-1))*Quick_Power(fac[i],MOD-2)%MOD;
    for(i=1;i<=n;i++)
        C[i]=Quick_Power(2,((long long)i*(i-1)>>1)%(MOD-1))*Quick_Power(fac[i-1],MOD-2)%MOD;
    Get_Inv(B,inv_B,m);
    FFT(inv_B,m<<1,1);
    FFT(C,m<<1,1);
    for(i=0;i<m<<1;i++)
        A[i]=(long long)inv_B[i]*C[i]%MOD;
    FFT(A,m<<1,MOD-2);
    long long inv=Quick_Power(m<<1,MOD-2);
    for(i=1;i<=n;i++)
        A[i]=A[i]*inv%MOD;
    cout<<A[n]*fac[n-1]%MOD<<endl;
    return 0;
}
时间: 2024-10-30 00:40:04

BZOJ 3456 城市规划 快速傅里叶变换的相关文章

BZOJ 3456: 城市规划

3456: 城市规划 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 640  Solved: 352[Submit][Status][Discuss] Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案,

BZOJ 3771: Triple [快速傅里叶变换 生成函数 容斥原理]

题意:n个物品,可以用1/2/3个不同的物品组成不同的价值,求每种价值有多少种方案(顺序不同算一种) 挖坑过会再写 生成函数系数为方案数,次数为价值 A(x) 选一个 B(x) A每项平方 选两个 C(x) A每项三次方 选三个 然后容斥原理算答案 注意计算的时候可以一直用点值,最后在变系数表示 #include <iostream> #include <cstdio> #include <string> #include <algorithm> #incl

BZOJ 3456 城市规划 多项式求ln

题意:链接 方法:多项式求ln 解析: 毒瘤题的倒数第二个- -! md毒瘤题都做完后再回来写题解真是爽歪歪 先看这道题怎么做. 首先一个简单无向图的边的个数是C(n,2),然后那么我们的选择就有2C(n,2)种. 然后我们再考虑简单无向连通图的方案数为fi. f[i]=2C(i,2)?∑i?1j=1f[j]?C(i?1,j?1)?2C(i?j,2) 上面的式子其实没啥卵用- 现在我们这么来考虑. 看如上大爷给出的PPT. 其实这个正体现了划分和被划分的关系. 对于简单无向图来说,简单无向连通图

bzoj 3456: 城市规划【NTT+多项式求逆】

参考:http://blog.miskcoo.com/2015/05/bzoj-3456 首先推出递推式(上面的blog讲的挺清楚的),大概过程是正难则反,设g为n个点的简单(无重边无自环)无向图数目,显然边数是\( C_{n}^{2} \),所以\( g(n)=2^{C_{n}^{2}} \),那么f[n]=g[n]-n个点的简单(无重边无自环)无向不连通图数目,后面那部分可以枚举1所在联通块的1点数,当这个块有i个点时,方案数为从n-1个点中选出i-1个(减去点1)* f[i](这i个点组成

【BZOJ 3456】 3456: 城市规划 (NTT+多项式求逆)

3456: 城市规划 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 658  Solved: 364 Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一

BZOJ 2179 FFT快速傅立叶 ——FFT

[题目分析] 快速傅里叶变换用于高精度乘法. 其实本质就是循环卷积的计算,也就是多项式的乘法. 两次蝴蝶变换. 二进制取反化递归为迭代. 单位根的巧妙取值,是的复杂度成为了nlogn 范德蒙矩阵计算逆矩阵又减轻了拉格朗日插值法的复杂度. 十分神奇. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #includ

一维快速傅里叶变换代码

上一篇随笔,简要写了一下FFT中数组重新排序的算法.现在把完整的FFT代码分享给大家(有比较详细的注释). /*2015年11月10日于河北工业大学*/ #include <complex>#include <iostream.h>#include <math.h>#include <stdlib.h>const int N=8;      //数组的长度const double PI=3.141592653589793; //圆周率const double

codeforces #250E The Child and Binary Tree 快速傅里叶变换

题目大意:给定一个集合S,对于i=1...m求有多少二叉树满足每个节点的权值都在集合S中且权值和为i 构造答案多项式F(x)和集合S的生成函数C(x),那么 根节点的左子树是一棵二叉树,右子树是一棵二叉树,本身的权值必须在集合S中,此外还有空树的情况 故有F(x)=F2(x)C(x)+1 解得F(x)=1±1?4C(x)√2C(x)=21±1?4C(x)√ 若等式下方取减号则分母不可逆,舍去 得到F(x)=21+1?4C(x)√ 有关多项式求逆和多项式开根的内容参见Picks的博客 CF上每个点

快速傅里叶变换(FFT)算法【详解】

快速傅里叶变换(Fast Fourier Transform)是信号处理与数据分析领域里最重要的算法之一.我打开一本老旧的算法书,欣赏了JW Cooley 和 John Tukey 在1965年的文章中,以看似简单的计算技巧来讲解这个东西. 本文的目标是,深入Cooley-Tukey  FFT 算法,解释作为其根源的“对称性”,并以一些直观的python代码将其理论转变为实际.我希望这次研究能对这个算法的背景原理有更全面的认识. FFT(快速傅里叶变换)本身就是离散傅里叶变换(Discrete