P6295 有标号 DAG 计数
先来看个弱化版的题目:
BZOJ2863
就是这道题的题目,只是不需要弱联通,还有数据范围在 3000。
怎么做?
有向无环图有一个经典的处理方式,就是拓扑排序,每次找出入度为
对于这些入度为
其中
然后就是,这个式子要
这里赠送一个技巧:
这个有什么用呢?就是把
那么有:
将跟
这不久好起来了,这不就好起来了?
令生成函数
那么有:
等一下,为什么是这样的,理论上来说多项式乘法不应该下标从
注意:当
还有为什么加一,因为
那么就可以解了,解得:
你以为这就结束了那你就错了,还有一个任务没完成,
其实这个很好想到(不就是城市规划吗),一般图一定是弱连通图的
这不就是裸的
时间复杂度
Code:
#include<bits/stdc++.h>
#define I inline
#define RI register int
#define rep(i,a,b) for(RI i=a;i<=b;++i)
#define dow(i,a,b) for(RI i=a;i>=b;--i)
using namespace std;
const int N=4e5+5,mo=998244353;
I int add(int a,int b){ return a+b>=mo?a+b-mo:a+b; }
I int sub(int a,int b){ return a-b<0?a-b+mo:a-b; }
I int mul(int a,int b){ return (long long)a*b%mo; }
I int fast(int a,int b=mo-2){ RI res=1;while(b) b&1&&(res=mul(res,a)),a=mul(a,a),b>>=1; return res; }
int n,frac[N],ifac[N],r[N],a[N],b[N],c[N],d[N],e[N],f[N];
I void NTT(int a[],int lim,int op){
rep(i,1,lim-1) if(r[i]>i) swap(a[i],a[r[i]]);
for(RI i=1;i<lim;i<<=1){
RI now=fast(op==1?3:332748118,(mo-1)/(i<<1));
for(RI j=0;j<lim;j+=(i<<1)){
RI res=1;
rep(k,0,i-1){
RI x=a[j+k],y=mul(res,a[j+k+i]);
a[j+k]=add(x,y),a[j+k+i]=sub(x,y),res=mul(res,now);
}
}
}
RI now=fast(lim);
if(op==-1) rep(i,0,lim-1) a[i]=mul(a[i],now);
}
I void Inv(int a[],int b[],int n){
if(n==1) return b[0]=fast(a[0]),void(); Inv(a,b,n+1>>1);
RI lim=1,cnt=0;while(lim<=(n<<1)) lim<<=1,++cnt;rep(i,1,lim-1) r[i]=r[i>>1]>>1|(i&1)<<cnt-1;
rep(i,0,n-1) c[i]=a[i];rep(i,n,lim-1) c[i]=0;NTT(c,lim,1),NTT(b,lim,1);
rep(i,0,lim-1) b[i]=mul(b[i],sub(2,mul(c[i],b[i])));NTT(b,lim,-1);rep(i,n,lim-1) b[i]=0;
}
I void Ln(int a[],int b[],int n){
rep(i,0,n-2) d[i]=mul(a[i+1],i+1);Inv(a,f,n);
RI lim=1,cnt=0;while(lim<=(n<<1)) lim<<=1,++cnt;rep(i,1,lim-1) r[i]=r[i>>1]>>1|(i&1)<<cnt-1;
NTT(d,lim,1),NTT(f,lim,1);rep(i,0,lim-1) b[i]=mul(d[i],f[i]);NTT(b,lim,-1);
dow(i,n-1,1) b[i]=mul(b[i-1],fast(i));b[0]=0;
}
int main(){
scanf("%d",&n),frac[0]=1;rep(i,1,n) frac[i]=mul(frac[i-1],i);ifac[n]=fast(frac[n]);dow(i,n-1,0) ifac[i]=mul(ifac[i+1],i+1);
a[0]=1;rep(i,1,n) a[i]=mul(fast(fast(2,1ll*i*(i-1)/2%998244352)),ifac[i]),i&1&&(a[i]=mo-a[i]);
Inv(a,e,n+1);rep(i,1,n) e[i]=mul(e[i],fast(2,1ll*i*(i-1)/2%998244352));Ln(e,b,n+1);
rep(i,1,n) printf("%d\n",mul(frac[i],b[i]));return 0;
}