【CF715E】Complete the Permutations(容斥,第一类斯特林数)
【CF715E】Complete the Permutations(容斥,第一类斯特林数)
题面
CF
洛谷
给定两个排列\(p,q\),但是其中有些位置未知,用\(0\)表示。
现在让你补全两个排列,定义两个排列\(p,q\)之间的距离为每次选择\(p\)中两个元素交换,使其变成\(q\)的最小次数。
求距离恰好为\([0,n-1]\)的填数方案数。
加强的题目在\(BZOJ\)上有,戳这里。
题解
看到这道题目就觉得无比熟悉。回头翻了翻发现果然是省队集训的时候的题目。。。
果然都是原题啊。。。
如果排列已知,发现交换的最小次数显然就是沿着置换交换,交换次数为\(n-\)置换个数。那么考虑从\(p_i\)连边连向\(q_i\),那么要求的就是环的个数。
显然成链的中间的\(x-x\)边全部可以直接丢掉,那么只需要考虑最终的开头和结尾就知道这条链到底是什么类型的了。
那么边有四种:已知-已知,已知-\(0\),\(0\)-已知,\(0\)-\(0\)。
对于已经成环的部分,我们显然不需要再考虑的。那么我们要做的就是把已经存在的链给合并成环,还要凭空用\(0-0\)边构造出一些环。
设有\(k\)条链,\(x-0\)和\(0-x\)是分开考虑的,设\(g_i\)表示至少有\(i\)个环。
\]
其中\(m\)是\(0-0\)边的数量。
这里拿\(x-0\)边举例。首先选择若干个\(x-0\)边出来拼成\(x\)个环,枚举使用的边的个数组合数计算方案,然后把他们拼成环,环排列个数即第一类斯特林数。多出来的边随意拼接,显然他们需要找一个后继,即把\(0\)位置和另外一条边给拼起来,无论是选择另外一个\(0-0\)边来拼或者选择一个\(x-0\)边来拼都是可行的,因为每条边也只会有一个前驱,所以选择方案数是下降幂。\(0-x\)边是同理的。
设\(f_x\)为\(0-x\)边计算出来的恰好的结果,\(g_x\)为\(x-0\)边计算出来的恰好的结果。两者卷积后,得到的是恰好形成了\(x\)环的结果。但是此时还多出了一些\(0-0\)链,它们形成环的方案数还是斯特林数。因此再将卷积的结果和斯特林数卷积。
最终因为\(0-0\)之间无顺序关系,所以还要乘上一个阶乘。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 550
#define MOD 998244353
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,a[MAX],b[MAX],deg[MAX];
int f[MAX],g[MAX],h[MAX],ans[MAX];
int nt[MAX],cnt[4];
bool vis[MAX<<1];
int C[MAX][MAX],A[MAX][MAX],S[MAX][MAX];
void dfs(int u,int ff)
{
vis[u]=true;
if(nt[u])
{
if(!vis[nt[u]])dfs(nt[u],ff);
else cnt[2]+=1;
}
else
{
if(u>n&&ff>n)cnt[3]+=1;
else if(u<=n&&ff>n)cnt[0]+=1;
else if(u>n&&ff<=n)cnt[1]+=1;
}
}
void calc(int *f,int n)
{
for(int i=0;i<=n;++i)
for(int j=i;j<=n;++j)
add(f[i],1ll*C[n][j]*S[j][i]%MOD*A[n-j+cnt[3]][n-j]%MOD);
for(int i=0;i<=n;++i)
{
int t=0;
for(int j=i,d=1;j<=n;++j,d=MOD-d)
add(t,1ll*d*f[j]%MOD*C[j][i]%MOD);
f[i]=t;
}
}
int main()
{
n=read();
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+n;++i)vis[i]=true;
for(int i=1;i<=n;++i)
{
if(!a[i])a[i]=i+n;if(!b[i])b[i]=i+n;
vis[a[i]]=vis[b[i]]=false;
if(a[i]<=n||b[i]<=n)nt[a[i]]=b[i],++deg[b[i]];
}
for(int i=1;i<=n+n;++i)if(!vis[i]&&!deg[i])dfs(i,i);
for(int i=1;i<=n+n;++i)if(!vis[i])dfs(i,i);
C[0][0]=S[0][0]=A[0][0]=1;
for(int i=1;i<=n;++i)
{
A[i][0]=C[i][0]=1;
for(int j=1;j<=i;++j)
{
C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
A[i][j]=1ll*A[i][j-1]*(i-j+1)%MOD;
S[i][j]=(S[i-1][j-1]+1ll*(i-1)*S[i-1][j])%MOD;
}
}
calc(f,cnt[0]);calc(g,cnt[1]);
for(int i=0;i<=n;++i)
for(int j=0;j<=i;++j)
add(h[i],1ll*f[j]*g[i-j]%MOD);
for(int i=0;i<=n;++i)
for(int j=0;j<=i;++j)
add(ans[i],1ll*h[j]*S[cnt[3]][i-j]%MOD);
for(int i=0;i<=n;++i)ans[i]=1ll*ans[i]*A[cnt[3]][cnt[3]]%MOD;
for(int i=0;i<n;++i)printf("%d ",n-i-cnt[2]>=0?ans[n-i-cnt[2]]:0);
puts("");return 0;
}
【CF715E】Complete the Permutations(容斥,第一类斯特林数)的更多相关文章
- UVA11077 Find the Permutations —— 置换、第一类斯特林数
题目链接:https://vjudge.net/problem/UVA-11077 题意: 问n的全排列中多有少个至少需要交换k次才能变成{1,2,3……n}. 题解: 1.根据过程的互逆性,可直接求 ...
- ARC096 E Everything on It [容斥,斯特林数]
Atcoder 一个900分的题耗了我这么久--而且官方题解还那么短--必须纪念一下-- 思路 发现每种元素必须出现两次以上的限制极为恶心,所以容斥,枚举出现0/1次的元素个数分别有几个.设出现1次的 ...
- CF715E Complete the Permutations(第一类斯特林数)
题目 CF715E Complete the Permutations 做法 先考虑无\(0\)排列的最小花费,其实就是沿着置换交换,花费:\(n-\)环个数,所以我们主要是要求出规定环的个数 考虑连 ...
- Codeforces 715E - Complete the Permutations(第一类斯特林数)
Codeforces 题面传送门 & 洛谷题面传送门 神仙题.在 AC 此题之前,此题已经在我的任务计划中躺了 5 个月的灰了. 首先考虑这个最短距离是什么东西,有点常识的人(大雾)应该知道, ...
- 【UVA 11077】 Find the Permutations (置换+第一类斯特林数)
Find the Permutations Sorting is one of the most used operations in real life, where Computer Scienc ...
- CF715E—— Complete the Permutations
传送门:QAQQAQ 题意:给你两个$1$~$n$的排列,0表示该位置数字不确定,两两交换第一个排列中的元素使之变成第二个排列,令$s[x]$表示对于所有不同的两个排列,最少交换次数为$x$的序列有$ ...
- 【HDU 4372】 Count the Buildings (第一类斯特林数)
Count the Buildings Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- 【组合数学:第一类斯特林数】【HDU3625】Examining the Rooms
Examining the Rooms Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- 如何快速求解第一类斯特林数--nlog^2n + nlogn
目录 参考资料 前言 暴力 nlog^2n的做法 nlogn的做法 代码 参考资料 百度百科 斯特林数 学习笔记-by zhouzhendong 前言 首先是因为这道题,才去研究了这个玩意:[2019 ...
随机推荐
- Luogu P3825 [NOI2017]游戏
这道题看上去NPC啊,超级不可做的样子. 我们先分析一下简单的情形:没有\(x\)地图 此时每个地图由于限制掉一种汽车,那么显然只会有两种选择. 再考虑到限制的情况,那么大致做法就很显然了--2-SA ...
- python第二周。2019.4.13
1, 我绘制大蟒蛇就是..保存也对着呢,你要是打开文件的话,先闪个黑屏,再闪个白屏..自动退出,然后啥都没了. 我觉得是我代码编错了...再来一遍! 这次到可以,但是这个大蟒蛇好像没有回头... 刚才 ...
- 基于HTML5 Canvas 实现地铁站监控
伴随国内经济的高速发展,人们对安全的要求越来越高.为了防止下列情况的发生,您需要考虑安装安防系统: 提供证据与线索:很多工厂银行发生偷盗或者事故相关机关可以根据录像信息侦破案件,这个是非常重要的一个线 ...
- 分布式监控系统Zabbix-图形集中展示插件Graphtree安装笔记
Zabbix想要集中展示图像,唯一的选择是screen,后来zatree解决了screen的问题,但性能不够好.Graphtree 由OneOaaS开发并开源出来,用来解决Zabbix的图形展示问题, ...
- centos7.2部署vnc服务记录
不做过多介绍了,下面直接记录下centos7系统下安装配置vncserver的操作记录 0)更改为启动桌面或命令行模式 获取当前系统启动模式 [root@localhost ~]# systemctl ...
- #个人博客作业week3——微软必应词典的使用
产品的调研和评测 笔者使用的是win8的必应词典客户端. 首先打开客户端,用户界面的设计十分简洁,使用方便.但是词典主页与大多外语软件的设计相仿,例如有每日一句,每日阅读等模块,并没有令人感到新奇的地 ...
- 【补充】第一次个人项目出现的bug
新程序包下载(密码:4kp6) >>>>>直接上代码,问题出在随机分数的生成上,确实出现了一些非常鱼唇的错误,不过已经提交了就没办法了,在这里发出来仅供参考吧: 修改前: ...
- 【BUAA软件工程】第一次阅读作业
BUAA软件工程 第一次阅读作业 项目 内容 这个作业属于哪个课程? 北航软工 这个作业的要求在哪里? 第一次个人作业 我在这个课程的目标是? 学习高效严谨的软件工程开发过程,建立团队意识 这个作业在 ...
- personal project
words count program 统计文本文件的字符数,单词数和行数. 实现一个统计程序,他能正确的统计程序文件中的字符数,单词数和行数. 源码链接 https://github.com/sup ...
- maven配置私服
1先配置maven的配置文件 2在项目的pom.xml文件增加 <distributionManagement> <repository> <id>nexus-re ...