原题codeforces链接
链接放在这里啦,大家看懂之后记得自己写写代码补题呀!
蒟蒻第一次写题解,所以尽量写得通俗易懂一些,大家不懂随时评论区评论!大家一定要有耐心看完啊,相信大家看到最后一定可以理解的!不懂随时评论!
有什么觉得不好的地方一定要在评论区评论一下呀!互相成长互相进步!
题意,给你一个n个数的从0到n-1的一个排列,让你找到一共有多少个排列情况使得该排列每一子段的mex和原排列的mex相同。
Mex:一段中没有出现的最小的非负整数。
坑点:原排列也算作一种!不要忽略。
一.解题思路:
我们来思考原数组怎么样变化才能使得每段区间mex不变。
如果mex=x,那么[0,x-1]肯定在区间中出现过了,因此我们从0-n-1 枚举,使这些数字都包含在区间内部,得到一个使得mex>x的最小长度的区间,只要每一个mex>i(i=0~n-1)段的最小长度区间mex不变,那整体每一段的mex就不会变。
我来模拟一下这个过程,来帮助你理解
初始化区间左端点l=pos[0],区间右端点r=pos[0],此时0这个位置的Mex一定是1。
所以0这个位置不能再动,接着找1的位置
第一种情况:假设如果你当前枚举的这个数没当前区间内部的话
因为1没在0这个区间内部,更新区间成以1和0为边界的区间。
这个区间mex一定大于等于1。
而其他不包含这个区间的任何一个区间的mex都是小于1的。
那么这个1的位置也是不可以动的,因为如果1的位置改变了的话,那当前这段0-1区间位置就改变了。
那么各段区间的mex也就变了
1:原先mex小于1的区间(不包含1但包含0)可能变成mex大于等于1(若1变到这个区间里面)。
2:原先mex大于等于1的区间可能变成等于1(本来包含0和1,但是1变出去了)。
第二种情况:假设如果你当前枚举的这个数在当前区间内部的话
举个例子:假如你现在枚举到边界是0-1的区间,枚举2的时候2在其内部,结合之前的条件,那么2这个数可以和区间内部任何一个比他大的数字交换位置(它本身位置不变也算一种方案)。那么ans=(ans*能与2能交换的位置个数+1)(这个乘法可以看做分步计数法,每次可以交换的方法,都不会影响之前交换的方法,然后每个数字交换的方法的总乘积,就是最后方案数)
为什么可以交换呢?
因为只有包含1,2才会影响mex,如果包含1一定包含2的话(2在0~1区间内),那么2的位置的改变并不影响其他区间的mex。
原因:
- 首先如果2的位置变了->对1-0区间内部mex的影响,区间内部任何一子段都不可能同时包含0和1(因为这两个数是作为边界出现的),所以他们的mex均与该子段有无2没有关系
- ->对区间外部的和包含这段区间的区间就更没有影响了,因为不管2在区间内部怎么变都不能改变外部不包含2,和包含这段区间的区间一定包含2,2会起作用的一个结果。
为什么只能和比他大交换呢?:
1.比他小的数字作为边界,根据情况1不能动
2:比他小的数字不作为边界,但是之前当做第二种情况可以与比他大的数交换位置算过一次了,避免重复。
Ps:怕大家不懂,再模拟过程的进行一次,假设当前枚举到了3
第一种情况
若3没在区间内部,再更新边界,3对改变的贡献为1就是*1(感性理解就是没贡献)
因为3如果变了
那么各段区间的mex也就变了
1:原先mex小于等于3的区间(不包含3但包含0、1、2)可能变成mex大于3(3变到这个区间里面)。
2:原先mex大于3的区间可能变成小于等于3(本来包含0和1和2和3,但是3变出去了)。
第二种情况
若3在区间内部,那么3这个数可以和区间内部任何一个比他大的数字交换位置(它本身位置不变也算一种方案)。那么ans=(ans*能与3能交换的位置个数+1)(这个乘法可以看做分步计数法,每次可以交换的方法,都不会影响之前交换的方法,然后每个数字交换的方法的总乘积,就是最后方案数)
为什么可以交换呢?
因为只有包含1,2,3才会影响mex,如果包含1包含2一定包含3的话(1,2,3在当前区间内),那么3的位置的改变并不影响其他区间的mex。
原因:
- 首先如果3的位置变了->对区间内部mex的影响,区间内部任何一子段都不可能同时包含0和1和3(因为总有两个数是作为边界出现的),根据mex的性质,所以他们的mex均与该子段有无3没有关系.
- ->对区间外部的和包含这段区间的区间就更没有影响了,因为不管3在区间内部怎么变都不能改变外部不包含3,和包含这段区间的区间一定包含3,3会起作用的一个结果。
为什么只能和比他大交换呢?:
1.比他小的数字作为边界,根据情况1不能动
2:比他小的数字不作为边界,但是之前当做第二种情况可以与比他大的数交换位置算过一次了,避免重复。
综上:
二.代码思路:
设置初始l=pos[0],r=pos[0]
从1~n-1枚举数字。
- 若数字没在1~r之间,那么更新边界。
- 若数字在l~r之间,那么更新ans=ans*(当前区间长度-已经枚举过的数字数量之和
建议大家自己进行代码实现再来看我的代码,也是可以更好地锻炼代码能力!,也许你写的比我更好呢!也可以给博主提提建议哈!
代码
#include#include #include #include



