ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1349F1 Slime and Sequences

2021-07-25 18:34:39  阅读:227  来源: 互联网

标签:CF1349F1 排列 映射 子段 int 位置 Slime Sequences 序列


一、题目

点此看题

二、解法

下次再也不找这种阴间题做了,根本想不到好吗?

首先做一个简单的转化:考虑让 \(k-1\) 第一次出现的位置大于 \(k\) 最后一次出现的位置。

考虑构造映射去描述好序列,你发现转化后的条件是比较连贯的,因为 \(k-1\) 第一次出现的位置大于 \(k\) 最后一次出现的位置,而 \(k\) 第一次出现的位置大于 \(k+1\) 最后一次出现的位置。

所以我们构建的映射要能很好的描述位置这一信息,那么考虑把 \(1\) 的出现位置从大到小写下,\(2\) 的出现位置从大到小写下\(...\)然后你发现写完这不是一个排列吗?那我们映射把好序列映射到一个排列上去了!

再证明所有排列都能映射回一个好序列,我们把原排列划分成若干个极长下降子段,第一个子段就代表 \(1\) 的所有出现位置,第二个子段就代表 \(2\) 的所有出现位置\(...\)以此类推就能映射到好序列上去。

那么得到结论:好序列能和排列一一映射


剩下的问题就是计数了,不难看出这是一个贡献法,我们考虑在排列上计数,考虑前面有 \(j-1\) 个下降子段那么这个数就是 \(j\),那么我们考虑每个位置的贡献,把前面和后面分开,先选出 \(i\) 个数放在前面,后面的数随便排列,然后前 \(i\) 个数的方案中需要存在 \(j-1\) 对 \(a_i<a_{i+1}\):

\[ans_j=\sum_{i=j}^n E(i,j-1)\cdot {n\choose i}\cdot (n-i)! \]

这里补充一下前置芝士,\(E(n,k)\) 表示 \(n\) 个数的排列有 \(k\) 对 \(a_i<a_{i+1}\) 的方案数,又称欧拉数,这个东西可以递推,考虑在 \(n-1\) 个数的基础上新插入一个 \(n\) 的影响:

  • 如果不会带来相邻顺序对的新增,那么可以插入在原来 \(k\) 对的空隙,或者插入到序列的开头,有 \(k+1\) 种方案,从 \(E(n-1,k)\) 处转移而来。
  • 如果会使相邻顺序对增加 \(1\),那么不能在原来 \(k-1\) 对的空隙中插入,也不能在序列的开头处插入,有 \(n-k\) 种方案,从 \(E(n-1,k-1)\) 处转移而来。

所以 \(E(n,k)=(k+1)\cdot E(n-1,k)+(n-k)\cdot E(n-1,k-1)\)

三、总结

计数中重要的方法是映射法,考虑原问题能不能映射到一些简单的模型中。此外,本题重要的是一个存在性限制,但不能转化所有性限制,转化为单点性限制就好做了很多。

插入法是解决排列计数的重要方法,通常是插入新增的元素考虑它的影响。

#include <cstdio>
const int M = 5005;
const int MOD = 998244353;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,o[M][M],fac[M],inv[M];
void init()
{
	fac[0]=inv[0]=inv[1]=1;
	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
	for(int i=2;i<=n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD;
}
signed main()
{
	n=read();init();
	for(int i=1;i<=n;i++)
		o[i][0]=1;
	for(int i=2;i<=n;i++)
		for(int j=1;j<i;j++)
			o[i][j]=o[i-1][j]*(j+1)+o[i-1][j-1]*(i-j),o[i][j]%=MOD;
	for(int j=1;j<=n;j++)
	{
		int ans=0;
		for(int i=j;i<=n;i++)
			ans=(ans+o[i][j-1]*fac[n]%MOD*inv[i])%MOD;
		printf("%lld ",ans);
	}
}

标签:CF1349F1,排列,映射,子段,int,位置,Slime,Sequences,序列
来源: https://www.cnblogs.com/C202044zxy/p/15058538.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有