试题来源
  2013中国国家集训队第二次作业
问题描述
  刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
  刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.
  为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
  好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
  由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
输入格式
  仅一行一个整数n(<=130000)
输出格式
  仅一行一个整数, 为方案数 mod 1004535809.
样例输入
3
样例输出
4
样例输入
4
样例输出
28
样例输入
100000
样例输出
829847355
数据规模和约定
  对于 20%的数据, n <= 10
  对于 40%的数据, n <= 1000
  对于 60%的数据, n <= 30000
  对于 80%的数据, n <= 60000
  对于 100%的数据, n <= 130000
【分析】
非常巧妙的题目。
首先可以推递推式,用f(n) = 2^C(n,2) - sigma{(2 ^ C(n - i, 2)) * C(n - 1, i - 1) * f(i) |  1<= i <n  }
相当于选定一个点不动,逐步扩大该点所在的联通快的大小。
可以保证不会出现重复。
经过化简将C(n-1,i-1)中的(n-1)!提出来以后,可以通过一种非常巧妙的构造卷积的方式解决问题(详见代码)。
为什么可以用FFT?。。。。FFT怎么取模啊,不会QAQ。
 /*
宋代朱敦儒
《西江月·世事短如春梦》
世事短如春梦,人情薄似秋云。不须计较苦劳心。万事原来有命。
幸遇三杯酒好,况逢一朵花新。片时欢笑且相亲。明日阴晴未定。
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <string>
#include <ctime>
#define LOCAL
const int MAXN = * * + ;
const long long MOD = ;//费马数论变换的费马素数
long long G = ;//元根
using namespace std;
typedef long long ll;
ll x1[MAXN], x2[MAXN];
ll data[MAXN], Ans[MAXN];
ll f[MAXN], I[MAXN], nI[MAXN], C[MAXN];
ll inv2[MAXN], wn[MAXN], Inv[MAXN]; ll pow(ll a, ll b){
if (b == ) return % MOD;
if (b == ) return a % MOD;
ll tmp = pow(a, b / );
if (b % == ) return (tmp * tmp) % MOD;
else return ((tmp * tmp) % MOD * (a % MOD)) % MOD;
}
ll exgcd(ll a, ll b, ll &x, ll &y){
if (b == ){x = 1ll; y = ; return a;}
ll tmp = exgcd(b, a % b, y, x);
y -= x * (a / b);
return tmp;
}
ll inv(ll a, ll p){
ll x, y;
ll tmp = exgcd(a, p, x, y);
return ((x % MOD) + MOD) % MOD;
}
void change(ll *x, int len, int loglen){
for (int i = ; i < len; i++){
int t = i, k = , tmp = loglen;
while (tmp--) {k = (k << ) + (t & ); t >>= ;}
if (k < i) swap(x[i], x[k]);
}
return;
}
void FNT(ll *x, int len, int loglen, int type){
if (type) change(x, len, loglen);
int t;
t = (type ? : ( << loglen));
for (int i = ; i < loglen; i++){
if (!type) t >>= ;
int l = , r = l + t;
while (l < len){
ll a, b;
ll tmp = 1ll, w = wn[t];
if (!type) w = Inv[t];
for (int j = l; j < l + t; j++){
if (type){
a = x[j] % MOD;
b = (x[j + t] * (tmp % MOD)) % MOD;
x[j] = (a + b) % MOD;
x[j + t] = ((a - b) % MOD + MOD) % MOD;
}else{
a = (x[j] + x[j + t]) % MOD;
b = ((((x[j] - x[j + t]) % MOD + MOD) % MOD) * tmp) % MOD;
x[j] = a;
x[j + t] = b;
}
tmp = (tmp * w) % MOD;
}
l = r + t;
r = l + t;
}
if (type) t <<= ;
}
if (!type){
change(x, len, loglen);
for (int i = ; i < len; i++) x[i] = (x[i] % MOD * inv(len, MOD)) % MOD;
}
}
//CDQ分治
void solve(int l, int r){
if (l == r){
//T为组合数的, I[l]为阶乘的模
f[l] = (C[l] - (I[l - ] * f[l]) % MOD + MOD) % MOD;
return;
}
int mid = (l + r) >> ;
solve(l, mid);
int len = max(mid - l + , r - mid), loglen = ;
while ((<<loglen) < ((r - l + ) << )) loglen++;//要把卷积分成两个部分 for (int i = ; i < (<<loglen); i++) x1[i] = x2[i] = ;
for (int i = l; i <= mid; i++) x1[i - l] = (nI[i - ] * f[i]) % MOD;
for (int i = ; i <= r - l; i++) x2[i] = (C[i] * nI[i]) % MOD; FNT(x1, (<<loglen), loglen, );
FNT(x2, (<<loglen), loglen, );
for (int i = ; i < (<<loglen); i++) x1[i] = (x1[i] * x2[i]) % MOD;
FNT(x1, (<<loglen), loglen, );
for (int i = mid + ; i <= r; i++) f[i] = (f[i] + x1[i - l] % MOD) % MOD;
solve(mid + , r);
}
int n;
void init(){
scanf("%d", &n);
inv2[] = ;
inv2[] = inv(, MOD);
//预处理2的阶乘的逆元
for (int i = ; i <= n; i++) inv2[i] = (inv2[i - ] * inv2[]) % MOD;
for (int i = ; i <= * n; i++){
if (i != && (MOD - ) / ( * i) == (MOD - ) / ( * (i - ))){
wn[i] = wn[i - ];
Inv[i] = Inv[i - ];
}else{
wn[i] = pow(G, (MOD - ) / ( * i)) % MOD;
Inv[i] = inv(wn[i], MOD) % MOD;
}
}
I[] = nI[] = ;//分别代表阶乘和阶乘的-1次方
for (int i = ; i <= n; i++){
I[i] = (long long)(i * I[i - ]) % MOD;
nI[i] = (inv((long long)i, MOD) * nI[i - ]) % MOD;
//printf("%lld\n", nI[i]);
}
//预处理组合数2^C(n, 2)
for (int i = ; i <= n; i++){
C[i] = pow(2ll, (long long)((long long)i * (i - )) / ) % MOD;
//printf("%lld\n", C[i]);
}
} int main() { init();
solve(, n);
printf("%lld\n", f[n]);
return ;
}

【BZOJ3456】【CDQ分治+FNT】城市规划的更多相关文章

  1. 【BZOJ3456】轩辕朗的城市规划 无向连通图计数 CDQ分治 FFT 多项式求逆 多项式ln

    题解 分治FFT 设\(f_i\)为\(i\)个点组成的无向图个数,\(g_i\)为\(i\)个点组成的无向连通图个数 经过简单的推导(枚举\(1\)所在的连通块大小),有: \[ f_i=2^{\f ...

  2. 【BZOJ-3456】城市规划 CDQ分治 + NTT

    题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...

  3. [BZOJ 3456]城市规划(cdq分治+FFT)

    [BZOJ 3456]城市规划(cdq分治+FFT) 题面 求有标号n个点无向连通图数目. 分析 设\(f(i)\)表示\(i\)个点组成的无向连通图数量,\(g(i)\)表示\(i\)个点的图的数量 ...

  4. 【教程】简易CDQ分治教程&学习笔记

    前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦!       CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...

  5. BZOJ 2683 简单题 ——CDQ分治

    [题目分析] 感觉CDQ分治和整体二分有着很本质的区别. 为什么还有许多人把他们放在一起,也许是因为代码很像吧. CDQ分治最重要的是加入了时间对答案的影响,x,y,t三个条件. 排序解决了x ,分治 ...

  6. HDU5618 & CDQ分治

    Description: 三维数点 Solution: 第一道cdq分治...感觉还是很显然的虽然题目不能再傻逼了... Code: /*=============================== ...

  7. 初识CDQ分治

    [BZOJ 1176:单点修改,查询子矩阵和]: 1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 200 ...

  8. HDU5322 Hope(DP + CDQ分治 + NTT)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5322 Description Hope is a good thing, which can ...

  9. BZOJ4170 极光(CDQ分治 或 树套树)

    传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...

随机推荐

  1. 白帽子讲Web安全1.pdf

    第一章 我的安全世界观 安全是一个持续过程 6种威胁:Spoofing(伪装).Tampering(篡改).Repudiation(抵赖).InformationDisclosure(信息泄漏).De ...

  2. android camera(一):camera模组CMM介绍

    一.摄像头模组(CCM)介绍: 1.camera特写 摄像头模组,全称CameraCompact Module,以下简写为CCM,是影像捕捉至关重要的电子器件.先来张特写,各种样子的都有,不过我前一段 ...

  3. C语言调用汇编实现字符串对换

    1. 前面配置arm交叉编译环境. 2. 配置好qemu-arm C语言代码string-switch.c: #include <stdio.h> #include <stdlib. ...

  4. mysql常用的一些命令,用于查看数据库、表、字段编码

    1.查看数据库支持的所有字符集         show character set;或show char set; 2.查看当前状态 里面包括当然的字符集设置         status或者\s ...

  5. VirtualBox安装Ghost XP

    http://jingyan.baidu.com/album/5d368d1e1a88b73f60c05721.html?picindex=1

  6. typeof和instanceof 运算符

    instanceof运算符与typeof运算符相似,用于识别正在处理的对象的类型,但是在使用 typeof 运算符时采用引用类型存储值会出现一个问题. 无论引用的是什么类型的对象,它都返回 " ...

  7. android设备连接不上电脑的解决方法

    先检查手机usb调试是否开启,已经开启还是连不上按照以下步骤操作: 1. 打开cmd,输入adb devices  查看设备是否连接 2.服务未启动,先杀掉服务:adb kill-server 3.启 ...

  8. C#环境下的数值计算库:MathNet

    下面用一个简单的例子来说明MathNet的使用方法: 1. 进入MathNet官网找到数值计算库Math.NET Iridium(Numerics)并下载: 2. 将下载的文件解压缩,在目录下的Bin ...

  9. 像C++一样写JavaScript

    像C++一样写JavaScript C/C++/Java的include或import可以引用第3方文件和包. 这个功能在Html/Js里没有默认的实现. 假设我们有这样一个HTML文件index.h ...

  10. 5 Common Interview Mistakes that Could Cost You Your Dream Job (and How to Avoid Them)--ref

    There have been many articles on our site on software testing interviews. That is because, we, as IT ...