标签:重复 其他 数值 else print 计数 math http class
博主名字好听
考虑没有\(0\)的情况,对每个\(a_i\rightarrow b_i\)
计环的个数为\(m\),那么\(a,b\)的距离为\(n-m\),易证
再考虑题目
建立\(2n\)个点,\(p[1-n]\)表示位置,\(v[1-n]\)表示数值
对于\(a_i\neq 0,v_{a_i}\rightarrow p_i\),对于每个\(b_i\neq 0, p_i\rightarrow v_{b_i}\)
其中每个\(v_x\rightarrow p_y\)表示补全后\(a_y=x\),\(p_x\rightarrow v_y\)表示补全后\(b_x=y\)
此时图中存在一些链和环,计环的数量为\(c0\),暂时不必考虑
显然一条链或环,\(p\)点与\(v\)点交替出现
定义四类链:
以\(p\)开头,\(p\)结尾的链,计数为\(c1\)
以\(v\)开头,\(p\)结尾的链,计数为\(c2\)
以\(p\)开头,\(p\)结尾的链,计数为\(c3\)
以\(v\)开头,\(v\)结尾的链,计数为\(c4\)
环上要求\(p,v\)节点交替出现,先考虑\(1,2,3\)类链的连边方法
设\(f_i\)表示恰好有\(i\)个仅由\(1\)类链组成的环时,\(1\)类链出边的方案数
\(1\)类链要么连向\(1\)类链,要么连向\(3\)类链
我们发现恰好不好算,我们先设\(f_i\)保证有\(i\)个仅由\(1\)类链组成的环时,其他\(1\)类链出边随意选择的方案数
可以枚举从\(c1\)中选出\(j\)条链排成\(i\)个环,剩下的\(c_1-j\)条链可以连向\(1\)类链或\(3\)类链
得到方程
那么再将\(f_i\)更新为恰好的方案数
\(j\)个环的方案书被重复计数\(\dbinom{j}{i}\)
设g_i\(表示恰好有\)i$个仅由\(2\)类链组成的环时,\(2\)类链入边的方案数
同\(f_i\)求法
令\(h=f*g\)
那么除了环和\(4\)类链,还有下面这\(4\)种长链
\(1.1\)类链\(^n\rightarrow\) \(3\)类链\(\rightarrow\) \(2\)类链\(^n\)
\(2.1\)类链\(^n\rightarrow\) \(3\)类链
\(3.3\)类链\(\rightarrow\) \(2\)类链\(^n\)
\(4.3\)类链
有性质:
\(1.\)只包含一条\(3\)类链
\(1.\)开头和结尾都是\(p\)
考虑用\(4\)类链和长链连接成环,环中长链和\(4\)类链一定交替出现
设\(ans_i\)为最终图中有\(i\)个环的方案数,那么枚举仅由\(1\)类链和\(2\)类链组成的环数\(j\)
因为每条长链只包含一条\(3\)类链,所以给每条长链标号\(1-c3\)
表示每条长链后先接一条\(4\)类链,再成环
由于\(c3=c4\),所以长链后接\(4\)类链的方案数是\(c4!\)
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<‘0‘||ch>‘9‘)&&ch!=‘-‘;ch=getchar());
if(ch==‘-‘) f=0,ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
return f?x:-x;
}
const int N=2010,p=998244353;
int n,t1,t2;
int fac[N],ifac[N],inv[N],ans[N],ret[N];
int f[N],g[N],h[N];
int a[N],b[N];
int nxt[N],deg[N];
bool vis[N];
int c0,c1,c2,c3,c4;
int c[N][N],s[N][N],A[N][N];
inline void init(int n)
{
s[0][0]=c[0][0]=A[0][0]=fac[0]=1;
for(int i=1;i<=n;++i)
{
fac[i]=fac[i-1]*i%p;
c[i][0]=A[i][0]=1;
for(int j=1;j<=i;++j)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j])%p;
s[i][j]=(s[i-1][j-1]+(i-1)*s[i-1][j])%p;
A[i][j]=(A[i-1][j]+j*A[i-1][j-1])%p;
}
}
}
inline void work(int cnt,int *f)
{
for(int i=0;i<=cnt;++i)
{
for(int j=0;j<=cnt;++j)
{
f[i]=(f[i]+c[cnt][j]*s[j][i]%p*A[cnt-j+c3][cnt-j]%p);
}
}
for(int i=cnt;i>=0;--i)
{
for(int j=i+1;j<=cnt;++j)
{
f[i]=(f[i]-f[j]*c[j][i]%p+p)%p;
}
}
}
inline void dfs(int now,int s,int t)
{
vis[now]=1;
int to=nxt[now];
if(to)
{
if(vis[to]) ++c0;
else dfs(to,s,t^1);
}
else
{
if(!s&&t) ++c1;
else if(s&&!t) ++c2;
else if(s&&t) ++c3;
else ++c4;
}
}
inline void main()
{
n=read();init(n<<1);
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) b[i]=read();
for(int i=1;i<=n;++i)
{
if(a[i]) nxt[a[i]+n]=i,++deg[i];
if(b[i]) nxt[i]=b[i]+n,++deg[b[i]+n];
}
for(int i=1;i<=2*n;++i)
if(!vis[i]&&!deg[i]) dfs(i,i>n,i>n);
for(int i=1;i<=2*n;++i)
if(!vis[i]) dfs(i,i>n,i>n);
work(c1,f);work(c2,g);
for(int i=0;i<=n;++i)
{
for(int j=0;j<=i;++j)
{
h[i]=(h[i]+f[j]*g[i-j]%p)%p;
}
}
for(int i=0;i<=n;++i)
{
for(int j=0;j<=i;++j)
{
ans[i]=(ans[i]+h[j]*s[c3][i-j]%p*fac[c4]%p)%p;
}
}
for(int i=0;i<n;++i)
if(n-i-c0>=0) ret[i]=ans[n-i-c0];
for(int i=0;i<n;++i) printf("%lld ",ret[i]);
}
}
signed main()
{
red::main();
return 0;
}
标签:重复 其他 数值 else print 计数 math http class
原文地址:https://www.cnblogs.com/knife-rose/p/13055457.html