有标号的DAG计数系列

有标号的DAG计数I

题意

给定一正整数\(n\),对\(n\)个点有标号的有向无环图(可以不连通)进行计数,输出答案\(mod \ 10007\)的结果。\(n\le 5000\)

题解

显然是\(O(n^2)\)来做。

设\(f(i)\)表示\(i\)个点有标号的有向无环图的个数。而\(DAG\)中的特殊点显然只有两种,要么是出度为\(0\),要么入度为\(0\)。随便枚举哪一种都行,这里枚举入度为\(0\)的点。

那么得到式子:

\[f(n)=\sum_{i=1}^nC_n^if(n-i)2^{i(n-i)}
\]

显然这样子枚举出来的并不是入度个数恰好为枚举个数的答案,所以需要容斥,也就是:

\[f(i)=\sum_{j=1}^n(-1)^{j-1}C_i^jf(i-j)2^{j(i-j)}
\]

\(O(n^2)\)暴力\(dp\)即可。

有标号的DAG计数II

题意

给定一正整数\(n\),对\(n\)个点有标号的有向无环图(可以不连通)进行计数,输出答案\(mod \ 998244353\)的结果。\(n\le 10^5\)

题解

推导同上题式子。考虑接着拆。

首先把\(2^{j(i-j)}\)给拆了,\(j(i-j)=i^2/2-j^2/2-(i-j)^2/2\)

这样子令\(t=\sqrt 2\),也就是\(2\)在模意义下的二次剩余。

接着拆式子:

\[\begin{aligned}
f(i)&=\sum_{j=1}^n(-1)^{j-1}C_i^jf(i-j)2^{j(i-j)}\\
&=\sum_{j=1}^n(-1)^{j-1}\frac{i!}{j!(i-j)!}f(i-j)t^{i^2-j^2-(i-j)^2}\\
&=\sum_{j=1}^n \frac{(-1)^{j-1}}{j!t^{j^2}}*\frac{f(i-j)}{(i-j)!t^{(i-j)^2}}*i!*t^{i^2}\\
\frac{f(i)}{i!t^{i^2}}&=\sum_{j=1}^n \frac{(-1)^{j-1}}{j!t^{j^2}}*\frac{f(i-j)}{(i-j)!t^{(i-j)^2}}
\end{aligned}
\]

令\(F(x)\)为\(\frac{f(i)}{i!t^{i^2}}\)的生成函数,\(G(x)\)为\(\frac{(-1)^{i-1}}{i!t^{i^2}}\)的生成函数,那么上面的等式写成:\(F(x)=G(x)F(x)+1\),因为卷积之后漏掉了\(F(0)\)。

那么解出\(F(x)=\frac{1}{1-G(x)}\),多项式求逆即可。

有标号的DAG计数III

题意

给定一正整数\(n\),对\(n\)个点有标号的有向无环图进行计数,这里加一个限制:此图必须是弱连通图。输出答案\(mod\ 10007\)的结果。\(n\le 5000\)

题解

又回到了一个\(O(n^2)\)的做法。设答案为\(g(i)\)。那么考虑这里和前面的区别在哪儿?这里要求弱连通。那么连通和不连通的考虑方法一般就是总数减去不合法,那么考虑什么东西是不合法的。

\[g(i)=f(i)-\sum_{j=1}^{i-1}C_{i-1}^{j-1}g(j)f(i-j)
\]

为啥呢?因为一旦不是弱连通了,那么必定有两个以上的联通块。我们枚举其中的一个包含\(1\)号点的联通块大小,那么这个方案数是\(g(j)\),而其他点随意构成\(DAG\),这样就是上述的式子了。

所以把\(I\)的代码蒯过来再加一个\(dp\)算\(g\)就好了。

有标号的DAG计数IV

题意

给定一正整数\(n\),对\(n\)个点有标号的有向无环图进行计数,这里加一个限制:此图必须是弱连通图。输出答案\(mod\ 998244353\)的结果。

题解

拆式子啊QwQ。

\[\begin{aligned}
g(i)&=f(i)-\sum_{j=1}^{i-1}C_{i-1}^{j-1}g(j)f(i-j)\\
&=f(i)-\sum_{j=1}^{i-1}\frac{(i-1)!}{(j-1)!(i-j)!}g(j)f(i-j)\\
\frac{g(i)}{(i-1)!}&=\frac{f(i)}{(i-1)!}-\sum_{j=1}^{i-1}\frac{g(j)}{(j-1)!}\frac{f(i-j)}{(i-j)!}
\end{aligned}
\]

这样子可以构建三个生成函数

\(G(x)=\sum \frac{g(i)}{(i-1)!}x^i\),\(F(x)=\sum \frac{f(i)}{(i-1)!}x^i\),\(H(x)=\sum \frac{f(i)}{i!}x^i\)。其中\(\sum\)都表示\(\sum_{i=1}^{\infty}\)。

卷积一下就是\(G(x)=F(x)-G(x)*H(x)\)。

化简一下就是\(G(x)=\frac{F(x)}{1+H(x)}\)。

多项式求逆即可。

I

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 10007
#define MAX 5050
int n,f[MAX],bin[MAX*MAX],jc[MAX],jv[MAX],inv[MAX];
int C(int n,int m){return jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int main()
{
scanf("%d",&n);f[0]=jc[0]=jv[0]=inv[0]=inv[1]=bin[0]=1;
for(int i=2;i<=n;++i)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%MOD;
for(int i=1;i<=n;++i)jv[i]=jv[i-1]*inv[i]%MOD;
for(int i=1;i<=n*n;++i)bin[i]=2*bin[i-1]%MOD;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
{
int tmp=C(i,j)*f[i-j]%MOD*bin[j*(i-j)]%MOD;
if(j&1)add(f[i],tmp);else add(f[i],MOD-tmp);
}
printf("%d\n",f[n]);
return 0;
}

II

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define REM 882049182
#define MAX 300000
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int r[MAX],W[MAX];
void NTT(int *P,int opt,int N)
{
int l=0;for(int i=1;i<N;i<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
{
int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
int A[MAX],B[MAX];
void Inv(int *a,int *b,int len)
{
if(len==1){b[0]=fpow(a[0],MOD-2);return;}
Inv(a,b,len>>1);
for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
NTT(A,1,len<<1);NTT(B,1,len<<1);
for(int i=0;i<len<<1;++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
NTT(A,-1,len<<1);
for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
for(int i=0;i<len<<1;++i)A[i]=B[i]=0;
}
int jc[MAX],jv[MAX],inv[MAX];
int N,n,F[MAX],G[MAX];
int main()
{
scanf("%d",&n);jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
for(N=1;N<=n;N<<=1);G[0]=1;int t=fpow(REM,MOD-2);
for(int i=1;i<N;++i)G[i]=1ll*jv[i]*fpow(t,1ll*i*i%(MOD-1))%MOD;
for(int i=1;i<N;++i)if(i&1)G[i]=MOD-G[i];
Inv(G,F,N);
printf("%lld\n",1ll*F[n]*jc[n]%MOD*fpow(REM,1ll*n*n%(MOD-1))%MOD);
return 0;
}

III

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 10007
#define MAX 5050
int n,f[MAX],g[MAX],bin[MAX*MAX],jc[MAX],jv[MAX],inv[MAX];
int C(int n,int m){return jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int main()
{
scanf("%d",&n);f[0]=jc[0]=jv[0]=inv[0]=inv[1]=bin[0]=1;
for(int i=2;i<=n;++i)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%MOD;
for(int i=1;i<=n;++i)jv[i]=jv[i-1]*inv[i]%MOD;
for(int i=1;i<=n*n;++i)bin[i]=2*bin[i-1]%MOD;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
{
int tmp=C(i,j)*f[i-j]%MOD*bin[j*(i-j)]%MOD;
if(j&1)add(f[i],tmp);else add(f[i],MOD-tmp);
}
for(int i=0;i<=n;++i)g[i]=f[i];
for(int i=1;i<=n;++i)
for(int j=1;j<i;++j)
add(g[i],MOD-C(i-1,j-1)*g[j]%MOD*f[i-j]%MOD);
printf("%d\n",g[n]);
return 0;
}

IV

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define REM 882049182
#define MAX 300000
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int r[MAX],W[MAX];
void NTT(int *P,int opt,int N)
{
int l=0;for(int i=1;i<N;i<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
{
int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
int A[MAX],B[MAX];
void Inv(int *a,int *b,int len)
{
if(len==1){b[0]=fpow(a[0],MOD-2);return;}
Inv(a,b,len>>1);
for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
NTT(A,1,len<<1);NTT(B,1,len<<1);
for(int i=0;i<len<<1;++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
NTT(A,-1,len<<1);
for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
for(int i=0;i<len<<1;++i)A[i]=B[i]=0;
}
int jc[MAX],jv[MAX],inv[MAX];
int N,n,F[MAX],G[MAX],H[MAX],P[MAX];
int main()
{
scanf("%d",&n);jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
for(N=1;N<=n;N<<=1);G[0]=1;int t=fpow(REM,MOD-2);
for(int i=1;i<N;++i)G[i]=1ll*jv[i]*fpow(t,1ll*i*i%(MOD-1))%MOD;
for(int i=1;i<N;++i)if(i&1)G[i]=MOD-G[i];
Inv(G,F,N);
for(int i=1;i<N;++i)F[i]=1ll*F[i]*jc[i]%MOD*fpow(REM,1ll*i*i%(MOD-1))%MOD;
for(int i=1;i<N;++i)H[i]=1ll*F[i]*jv[i]%MOD;H[0]=1;
for(int i=1;i<N;++i)F[i]=1ll*F[i]*jv[i-1]%MOD;F[0]=0;
Inv(H,P,N);
NTT(F,1,N<<1);NTT(P,1,N<<1);
for(int i=0;i<N<<1;++i)G[i]=1ll*F[i]*P[i]%MOD;
NTT(G,-1,N<<1);
printf("%lld\n",1ll*G[n]*jc[n-1]%MOD);
return 0;
}

有标号的DAG计数(FFT)的更多相关文章

  1. 【题解】有标号的DAG计数2

    [HZOI 2015] 有标号的DAG计数 II \(I\)中DP只有一个数组, \[ dp_i=\sum{i\choose j}2^{j(i-j)}dp_{i-j}(-1)^{j+1} \] 不会. ...

  2. COGS2356 【HZOI2015】有标号的DAG计数 IV

    题面 题目描述 给定一正整数n,对n个点有标号的有向无环图进行计数. 这里加一个限制:此图必须是弱连通图. 输出答案mod 998244353的结果 输入格式 一个正整数n. 输出格式 一个数,表示答 ...

  3. COGS2355 【HZOI2015】 有标号的DAG计数 II

    题面 题目描述 给定一正整数n,对n个点有标号的有向无环图(可以不连通)进行计数,输出答案mod 998244353的结果 输入格式 一个正整数n 输出格式 一个数,表示答案 样例输入 3 样例输出 ...

  4. 【题解】有标号的DAG计数4

    [HZOI 2015] 有标号的DAG计数 IV 我们已经知道了\(f_i\)表示不一定需要联通的\(i\)节点的dag方案,考虑合并 参考[题解]P4841 城市规划(指数型母函数+多项式Ln),然 ...

  5. 【题解】有标号的DAG计数3

    [HZOI 2015] 有标号的DAG计数 III 我们已经知道了\(f_i\)表示不一定需要联通的\(i\)节点的dag方案,考虑合并 参考[题解]P4841 城市规划(指数型母函数+多项式Ln), ...

  6. 【题解】有标号的DAG计数1

    [HZOI 2015] 有标号的DAG计数 I 设\(f_i\)为\(i\)个点时的DAG图,(不必联通) 考虑如何转移,由于一个DAG必然有至少一个出度为\(0\)的点,所以我们钦定多少个出度为\( ...

  7. COGS 2353 2355 2356 2358 有标号的DAG计数

    不用连通 枚举入度为0的一层 卷积 发现有式子: 由$n^2-i^2-(n-i)^2=2*i*(n-i)$ 可得$2^{i*(n-i)}=\frac{{\sqrt 2}^{(n^2)}}{{\sqrt ...

  8. 有标号的DAG计数 III

    Description 给定一正整数n,对n个点有标号的有向无环图进行计数,这里加一个限制:此图必须是弱连通图.输出答案 mod 10007 的结果. Solution 弱连通图即把边变成无向之后成为 ...

  9. 有标号的DAG计数 II

    Description 给定一正整数n,对n个点有标号的有向无环图(可以不连通)进行计数,输出答案mod 998244353的结果 Solution 考虑 \(O(n^2)\) DP 枚举出度为 \( ...

随机推荐

  1. anglarjs1.6.3+owin 实现验证之一:统一拒绝非登录访问。

    1.anglarjs端在app.js(即anglar的入口js),注册.factory("messageService",使得每次来自html客户端的请求都能带有一个值,如AKey ...

  2. [转]zookeeper-端口说明

    一.zookeeper有三个端口(可以修改) 1.2181 2.3888 3.2888 二.3个端口的作用 1.2181:对cline端提供服务 2.3888:选举leader使用 3.2888:集群 ...

  3. CF 799B T-shirt buying

    一道超级水的练习STL的题目 题目大意:有\(n\)件T恤,每件T恤都分别有价格(每件衣服的价格不重复).前面的颜色.背部的颜色三种属性.接下来有\(m\)个人每个人都有一种喜欢的颜色,他们按先后顺序 ...

  4. Luogu P3374 【模板】树状数组 1

    真正的模板题. 树状数组的思想很简单(不如说背代码更简单),每个节点记录多个节点的信息(每个点存x&(-x)个). 道理可以参见很多大佬的博客,最后前缀和的思想搞一下就好了.不想说也不会说. ...

  5. REST-framework快速构建API--分页

    分页简介 当数据量特别大的时候,我们通过API获取数据会非常慢,所以此时我们需要将数据"分批次"取出来,这里的"分批次"就是,分页! REST框架支持自定义分页 ...

  6. netfilter/iptables 简介

    netfilter 是 Linux 内置的一种防火墙机制,我们一般也称之为数据包过滤机制.iptables 则是一个命令行工具,用来配置 netfilter 防火墙.下图展示了一个带有防火墙的简单网络 ...

  7. GlusterFS分布式存储系统中更换故障Brick的操作记录

    前面已经介绍了GlusterFS分布式存储集群环境部署记录,现在模拟下更换故障Brick的操作: 1)GlusterFS集群系统一共有4个节点,集群信息如下: 分别在各个节点上配置hosts.同步好系 ...

  8. linux上启动tomcat远程不能访问

    linux上关闭防火墙同样访问不了,执行iptables -f即可. 你试一试这个“iptables -F”然后再访问,如果能够访问了,那么需要执行“firewall-cmd --add-port=8 ...

  9. beta版说明书

    项目名称:GoGoing 软件使用说明: 在主界面是可以点击选择景点门票区间来选择景点,同时也可搜索景点显示信息. 还可以通过定位功能显示附近景点. 点开门票区间后是一些景点的图片和简介,还可以通过距 ...

  10. JQuery监听页面滚动总结

    1.当前滚动的地方的窗口顶端到整个页面顶端的距离: var winPos = $(window).scrollTop(); 2.获取指定元素的页面位置: $(val).offset().top; 3. ...