Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)

题目

Source

http://www.tsinsen.com/A1493

Description

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

Input

仅一行一个整数n(<=130000)

Output

仅一行一个整数, 为方案数 mod 1004535809.

Sample Input

3
4
100000

Sample Output

4
38
829847355

分析

楼教主男人八题也又一题是和这题一样,n个有标号点能构成的简单无向连通图数,不过这题题目数据大很多。做法如下:

  • 补集转化,设$f[n]$表示n个带标号的点能构成的简单图数,而只要利用$f[n]$减去不连通的数目就是要求的答案了。其中$f[n]=2^{n(n-1)/2}$,因为完全图有$n(n-1)/2$条边,对于每条边选或不选来构成一张简单图。
  • $dp[n]$表示n个带标号的点能构成的简单无向连通图数
  • 考虑通过固定一个点,枚举这个点所在连通块的大小来转移:$dp[n]\ =\ f[n]-\sum_{i=1}^{n-1}C_{n-1}^{i-1}dp[i]f[n-i]$
  • 整理成卷积形式:$d[n]\ =\ f[n]-(n-1)!\sum_{i=1}^{n-1}((i-1)!)^{-1}d[i] \times ((n-i)!)^{-1}f[n-i]$
  • 最后就是用分治FFT来做了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 262144

//const long long P=50000000001507329LL; // 190734863287 * 2 ^ 18 + 1
const int P=1004535809; // 479 * 2 ^ 21 + 1
//const int P=998244353; // 119 * 2 ^ 23 + 1
const int G=3;

long long mul(long long x,long long y){
	return x*y%P;
}
long long qpow(long long x,long long k){
	long long ret=1;
	while(k){
		if(k&1) ret=mul(ret,x);
		k>>=1;
		x=mul(x,x);
	}
	return ret;
}

long long wn[25];
void getwn(){
	for(int i=1; i<=21; ++i){
		int t=1<<i;
		wn[i]=qpow(G,(P-1)/t);
	}
}

int len;
void NTT(long long y[],int op){
	for(int i=1,j=len>>1,k; i<len-1; ++i){
		if(i<j) swap(y[i],y[j]);
		k=len>>1;
		while(j>=k){
			j-=k;
			k>>=1;
		}
		if(j<k) j+=k;
	}
	int id=0;
	for(int h=2; h<=len; h<<=1) {
		++id;
		for(int i=0; i<len; i+=h){
			long long w=1;
			for(int j=i; j<i+(h>>1); ++j){
				long long u=y[j],t=mul(y[j+h/2],w);
				y[j]=u+t;
				if(y[j]>=P) y[j]-=P;
				y[j+h/2]=u-t+P;
				if(y[j+h/2]>=P) y[j+h/2]-=P;
				w=mul(w,wn[id]);
			}
		}
    }
    if(op==-1){
		for(int i=1; i<len/2; ++i) swap(y[i],y[len-i]);
		long long inv=qpow(len,P-2);
		for(int i=0; i<len; ++i) y[i]=mul(y[i],inv);
    }
}
void Convolution(long long A[],long long B[],int n){
	for(len=1; len<(n<<1); len<<=1);
	for(int i=n; i<len; ++i){
		A[i]=B[i]=0;
	}

	NTT(A,1); NTT(B,1);
	for(int i=0; i<len; ++i){
		A[i]=mul(A[i],B[i]);
	}
	NTT(A,-1);
}

long long A[MAXN],B[MAXN];

long long d[MAXN],f[MAXN]={1},fact[MAXN]={1},fact_inv[MAXN]={1};
/*
    d[n] = f[n]-fact[n-1]*Σ(fact_inv[i-1]*d[i]*f[n-i]*fact_inv[n-i])
*/
void cdq(int l,int r){
    if(l==r) return;
    int mid=l+r>>1;
    cdq(l,mid);
    for(int i=l; i<=mid; ++i){
        A[i-l]=mul(fact_inv[i-1],d[i]);
    }
    for(int i=mid-l+1; i<=r-l; ++i) A[i]=0;
    for(int i=0; i<=r-l; ++i){
        B[i]=mul(fact_inv[i],f[i]);
    }
    Convolution(A,B,r-l+1);
    for(int i=mid+1; i<=r; ++i){
        d[i]-=mul(fact[i-1],A[i-l]);
        if(d[i]<0) d[i]+=P;
    }
    cdq(mid+1,r);
}

int main(){
	getwn();
	for(int i=1; i<=130000; ++i){
        fact[i]=mul(fact[i-1],i);
        fact_inv[i]=qpow(fact[i],P-2);
        d[i]=f[i]=qpow(2,(i-1LL)*i/2);
	}
	cdq(1,130000);
	int n;
	while(~scanf("%d",&n)){
        printf("%lld\n",d[n]);
	}
	return 0;
}
时间: 2024-10-13 00:58:27

Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)的相关文章

HDU5322 Hope(DP + CDQ分治 + NTT)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5322 Description Hope is a good thing, which can help you conquer obstacles in your life, just keep fighting, and solve the problem below. In mathematics, the notion of permutation relates to the ac

BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关的量只有t = dp(j) - F(i) * T(j) , 我们要最小化它. dp(j)->y, T(j)->x, 那么y = F(i) * x + t, 就是给一些点和一个斜率...然后最小化截距, 显然维护下凸包就可以了. 然后因为无比坑爹的出题人....时间可以为负数, 所以要用平衡树维护(

bzoj1492--斜率优化DP+cdq分治

显然在某一天要么花完所有钱,要么不花钱. 所以首先想到O(n^2)DP: f[i]=max{f[i-1],(f[j]*r[j]*a[i]+f[j]*b[i])/(a[j]*r[j]+b[j])},j<i 其中f[j]*r[j]/(a[j]*r[j]+b[j])是第j天最多能买多少A券,B类似. 假如我们已经找到了最优的j,那么有f[i]=(f[j]*r[j]*a[i]+f[j]*b[i])/(a[j]*r[j]+b[j]) 令x[j]=f[j]*r[j]/(a[j]*r[j]+b[j]),y[j

bzoj 2726 [SDOI2012]任务安排(斜率DP+CDQ分治)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2726 [题意] 将n个任务划分成若干个块,每一组Mi任务花费代价(T+sigma{ tj }+s)*sima{ fi },j属于Mi,T为当前时间,问最小代价. [思路] 设f[i]为将前i个任务划分完成的最小费用,Ti Fi分别表示t和f的前缀和,则不难写出转移方程式: f[i]=min{ f[j]+(F[n]-F[j])*(T[i]-T[j]+s) },1<=j<=i-1 经过

斜率dp cdq 分治

f[i] = min { f[j] + sqr(a[i] - a[j]) } f[i]= min { -2 * a[i] * a[j] + a[j] * a[j] + f[j] } + a[i] * a[i] 由于a[i]不是单调递增的,不能直接斜率dp. 考虑有cdq分治来做,复杂度(nlog2n) 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm&

BZOJ4555求和(cdq分治+NTT)

题意: 输出f(n)对998244353(7 × 17 × 223 + 1)取模的结果.1 ≤ n ≤ 100000 其中S(i,j)是第二类Stirling数,即有i个球,丢到j个盒子中,要求盒子不为空的方案总数 S(i,j)=S(i-1,j-1)+j*S(i-1,j) (前面一项表示第i个球单独放到一个盒子中,后面一项表示放到前面j个盒子中的某一个) 分析: 首先这个n不是丧心病狂的大,所以感觉可以求i=1时的结果,i=2时的结果,i=3时的结果……,于是可以不看第一个Σ 我们考虑后面的这项

bzoj 1492 [NOI2007]货币兑换Cash(斜率dp+cdq分治)

Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目.答案保留3 位小数. Sample Input 3 100 1 1 1 1 2 2 2 2 3 Sample Output 225.000 HINT 测试数据设计使得精度误差不会超过10-7.对于40%的测试数据,满足N

HDU5730 Shell Necklace(DP + CDQ分治 + FFT)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5730 Description Perhaps the sea‘s definition of a shell is the pearl. However, in my view, a shell necklace with n beautiful shells contains the most sincere feeling for my best lover Arrietty, but

BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治

2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是