题目

题目大意

求\(N\)个点的简单无向图的方案数(有编号)。

结果对\(1004535809\)取模。


思考历程

感觉这个问题非常经典。

当时想到了一堆式子,但都觉得可能会有重和漏,于是弃掉了……

最终打了个纯得不能再纯的暴力,在本地开O3,将\(1\)到\(8\)的答案都跑出来,打了个表……


正解

正解的一部分似乎被我错过了。

显然是DP,设\(f_i\)表示大小为\(i\)的连通图个数,\(g_i\)表示大小为\(i\)的所有图的个数。

显然\(g_i=2^{C_n^2}\)

接下来是转移:用总体情况减去不连通的情况。对于不连通的情况,我们固定\(i\)不动,\(i\)在一个大小为\(j\)的连通块内,剩下的\(i-j\)个点以任意方式排列,但就是不与\(i\)所在的连通块相连。

综上所述,\(f_i=g_i-\sum_{j=1}^{i-1}C_{i-1}^{j-1}f_jg_{i-j}\)

为什么不重,为什么不漏?

直觉告诉我这是个感性理解的东西……不好用语言描述啊……

接下来化一下式子:\(f_i=g_i-(i-1)!\sum_{j=1}^{i-1}\frac{f_j}{(j-1)!}\frac{g_{i-j}}{(i-j)!}\)

设\(F_i=\frac{f_i}{(i-1)!} \ G_i=\frac{g_i}{i!}\),\(H_i=\sum_{j=1}^{i-1}F_jG_{i-j}\)

我们发现这是一个卷积的形式!

然后就是一个分治FFT(NTT)……(当然我之前不会)

不过实际上思想也比较简单,就是用CDQ分治的思想,用左边的东西计算对右边的贡献。

具体来说,用\([l,mid]\)影响\([mid+1,r]\),

也就是\((F_l,F_{l+1},...,F_{mid})\)乘上\((G_1,G_2,...,G_{r-l})\)。注意位置的对应关系……(想当初这东西调了我很久)

时间复杂度自然是\(O(n\lg^2 n)\)的。

当然,这道题用NTT当然更好。因为FFT有可怕的精度问题啊……

\(1004535809\)是NTT的模数,原根为\(3\)。取\(n\)次单位根的时候就直接\(3^\frac{mo-1}{n} \mod mo\)就是了。

NTT和FFT几乎一模一样,具体的理论部分,我想我就懒得涉猎了……


代码

可能和我讲的不太一样。在分治之前,我开到了\(2\)的幂……但似乎没个卵用……

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define PI 3.14159263538979
#define mo 1004535809
#define N 131073
long long my_pow(long long x,long long y){
long long res=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
res=res*x%mo;
return res;
}
int n,m;
long long fac[N],inv[N];
long long f[N],g[N],h[N];
int M;
long long a[N*4],b[N*4],c[N*4];
int rev[N*4];
inline void ntt(long long*a,int flag){
for (int i=0;i<M;++i)
if (i<rev[i])
swap(a[i],a[rev[i]]);
for (int i=1;i<M;i<<=1){
long long wn=my_pow(3,(mo-1)/(i*2));
if (flag==-1)
wn=my_pow(wn,mo-2);
for (int j=0;j<M;j+=i<<1){
long long wnk=1;
for (int k=j;k<j+i;++k,wnk=wnk*wn%mo){
long long x=a[k],y=wnk*a[k+i]%mo;
a[k]=(x+y)%mo;
a[k+i]=(x-y+mo)%mo;
}
}
}
long long invM=my_pow(M,mo-2);
if (flag==-1)
for (int i=0;i<M;++i)
a[i]=a[i]*invM%mo;
}
inline void calc(){
for (int i=0;i<M;++i){
int tmp=0;
for (int j=i,k=0;1<<k<M;j>>=1,++k)
tmp=tmp<<1|j&1;
rev[i]=tmp;
}
ntt(a,1),ntt(b,1);
for (int i=0;i<M;++i)
c[i]=a[i]*b[i];
ntt(c,-1);
}
void dfs(int l,int r){
if (l==r){
f[l]=(g[l]-h[l]%mo*fac[l-1]%mo+mo)%mo;
return;
}
int mid=l+r>>1;
dfs(l,mid);
for (M=1;M<=3*(mid-l);M<<=1);
memset(a,0,sizeof(long long)*M);
memset(b,0,sizeof(long long)*M);
for (int i=0;i<mid-l+1;++i)
a[i]=f[l+i]*inv[l+i-1]%mo;
for (int i=0;i<mid-l+mid-l+1;++i)
b[i]=g[i+1]*inv[i+1]%mo;
calc();
for (int i=mid-l;i<mid-l+mid-l+1;++i)
h[l+i+1]+=c[i];
dfs(mid+1,r);
}
int main(){
scanf("%d",&n);
fac[0]=1,inv[0]=1;
for (int i=1;i<=n;++i)
fac[i]=fac[i-1]*i%mo,inv[i]=my_pow(fac[i],mo-2);
for (int i=1;i<=n;++i)
g[i]=my_pow(2,1ll*i*(i-1)>>1);
for (m=1;m<n;m*=2);
dfs(1,m);
printf("%lld\n",f[n]);
return 0;
}

总结

DP能力还是要加强啊……

[JZOJ3303] 【集训队互测2013】城市规划的更多相关文章

  1. [JZOJ3302] 【集训队互测2013】供电网络

    题目 题目大意 给你一个有向图,每个点开始有一定的水量(可能为负数),可以通过边流到其它点. 每条边的流量是有上下界的. 每个点的水量可以增加或减少(从外界补充或泄出到外界),但是需要费用,和增加(减 ...

  2. 【loj2461】【2018集训队互测Day 1】完美的队列

    #2461. 「2018 集训队互测 Day 1」完美的队列 传送门: https://loj.ac/problem/2461 题解: 直接做可能一次操作加入队列同时会弹出很多数字,无法维护:一个操作 ...

  3. 【2018集训队互测】【XSY3372】取石子

    题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...

  4. 洛谷 P4463 - [集训队互测 2012] calc(多项式)

    题面传送门 & 加强版题面传送门 竟然能独立做出 jxd 互测的题(及其加强版),震撼震撼(((故写题解以祭之 首先由于 \(a_1,a_2,\cdots,a_n\) 互不相同,故可以考虑求出 ...

  5. UOJ#191. 【集训队互测2016】Unknown 点分治 分治 整体二分 凸包 计算几何

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ191.html 题目传送门 - UOJ191 题意 自行移步集训队论文2016中罗哲正的论文. 题解 自行 ...

  6. LOJ3069. 「2019 集训队互测 Day 1」整点计数(min_25筛)

    题目链接 https://loj.ac/problem/3069 题解 复数真神奇. 一句话题意:令 \(f(x)\) 表示以原点 \((0, 0)\) 为圆心,半径为 \(x\) 的圆上的整点数量, ...

  7. UOJ#191. 【集训队互测2016】Unknown

    题意:维护一个数列,每个元素是个二维向量,每次可以在后面加一个元素或者删除一个元素.给定P(x,y),询问对于[l,r]区间内的元素$S_i$,$S_i \times P$的最大值是多少. 首先简单地 ...

  8. 【集训队互测2015】Robot

    题目描述 http://uoj.ac/problem/88 题解 维护两颗线段树,维护最大值和最小值,因为每次只有单点查询,所以可以直接在区间插入线段就可以了. 注意卡常,不要写STL,用链表把同类修 ...

  9. EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

    享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了 ...

随机推荐

  1. Swift结构体和类

    Swift结构体 在Swift标准中,绝大多数的公开的类型都是结构体,而枚举和类只占很小的一部分 比如Bool.Int.Double.String.Array.Dictionary等常见的类型都是结构 ...

  2. wall -- 向所有人的终端发送消息

    总览 (SYNOPSIS) wall [ message ] 描述 (DESCRIPTION) Wall 向 所有 登录的 并且 mesg(1) 权限 设为 yes 的 用户 发送 消息. 消息可以 ...

  3. 遍历对象不能通过for循环因为对象无序 可以通过for -n

    遍历对象不能通过for循环因为对象无序  可以通过for -n var json={ "name":“小明”, “age”:“10”, “sex”:"男" }; ...

  4. python_django_urls模块与views模块请求访问过程

    diango接收到web请求后的在urls模块与views模块进行的过程操作: 匹配过程: urls拿到网址,在项目级urls中匹配,若在urlpatterns中存在,则跳转到应用级urls中匹配,若 ...

  5. 利用字节流文件生成包含多文件的zip文件

    InputStream[] inputStreamsList = new InputStream[jsonArr.size()]; String[] fileNameList = new String ...

  6. 10.Struts2值栈

    1.什么是值栈 * 值栈就相当于Struts2框架的数据的中转站,向值栈存入一些数据.从值栈中获取到数据. * ValueStack 是 struts2 提供一个接口,实现类 OgnlValueSta ...

  7. FTP 连接模式 (主动模式被动模式)

    FTP是有两种传输的模式的,主动模式和被动模式,一个完整的FTP文件传输需要建立两种类型的连接,一种为文件传输下命令,称为控制连接,另一种实现真正的文件传输,称为数据连接. 1. 控制连接客户端希望与 ...

  8. npm run 同时执行多个命令

    在项目中可能需要一套代码同时部署几套环境,每一次改动就需要同时打包N次.这时就需要能够一个命令同时打包多次,省去了很多麻烦. 这里我们需要用到 concurrently 这个 npm 包,能够实现我们 ...

  9. 虚拟IP---Linux下一个网卡配置多个IP

    转:http://blog.csdn.net/turkeyzhou/article/details/16971225 Linux下配置网卡ip别名何谓ip别名?用windows的话说,就是为一个网卡配 ...

  10. solr +zookeeper+tomcat 集群搭建

    最近需要搭建一个cloudSolr集群,写下记录.基础环境是在centos6.5 64bit 3个下载地址: 1. 下载Solr-4.x http://lucene.apache.org/solr/d ...