试题来源
  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. 破解安装 SecureCRT 7.0.2 for mac完美破解版,mac secureCRT , apple secureCRT

    mac secureCRT , apple secureCRT 下载地址:http://download.csdn.net/detail/guolichun/7733069 破解安装  SecureC ...

  2. GPGPU OpenCL/CUDA 高性能编程的10大注意事项

    转载自:http://hc.csdn.net/contents/content_details?type=1&id=341 1.展开循环 如果提前知道了循环的次数,可以进行循环展开,这样省去了 ...

  3. python 基础干货 01

    赋值的实现 a = 'abc' 1. 在内存中创建了'abc'字符串; 2. 在内存中创建了一个名为 a 的变量, 并把它指向刚才创建的'abc', 也就是a中保存着字符串的地址. b = a, 创建 ...

  4. Scanner类的.next()和.hashNext()方法

    使用Scanner类可以很方便地便获取用户的键盘输入,Scanner是一个基于正则表达式的文本扫描器,它可以从文件.输入流 .字符串中解析出基本类型值和字符串值.Scanner类提供了多个构造器,不同 ...

  5. Java如何等待子线程执行结束

    工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一个线程启动之后, 是异步的去执行需要执行的内容的, 不会影响主线 ...

  6. load 与initialize的调用顺序小结

    开发中实用方法固然是最贴近应用的,当一些程序原理还是要先搞清晰,根据查找的一些资料,总结了一些load与initialize的调用. APP启动到执行main函数之前,程序就执行了很多代码   执行顺 ...

  7. Java 5种字符串拼接方式性能比较

    http://blog.csdn.net/kimsoft/article/details/3353849 import java.util.ArrayList; import java.util.Li ...

  8. DataGridView减少闪烁的解决办法

    Reducing flicker, blinking in DataGridView http://www.codeproject.com/Tips/390496/Reducing-flicker-b ...

  9. Hadoop 2.4.0新特性介绍

    在2014年4月7日,Apache公布了Hadoop 2.4.0 .相比于hadoop 2.3.0,这个版本号有了一定的改进,突出的变化能够总结为下列几点(官方文档说明): 1 支持HDFS訪问控制列 ...

  10. jquerymobile知识点:select的动态帮定

    代码: <div data-role="navbar"> <ul> <li> <select name="select-choi ...