栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

(超详尽版,不懂随时评论)Codeforces Round #804 (Div. 2)C The Third Problem

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

(超详尽版,不懂随时评论)Codeforces Round #804 (Div. 2)C The Third Problem

原题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。

原因:

  1. 首先如果2的位置变了->对1-0区间内部mex的影响,区间内部任何一子段都不可能同时包含0和1(因为这两个数是作为边界出现的),所以他们的mex均与该子段有无2没有关系
  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。

原因:

  1. 首先如果3的位置变了->对区间内部mex的影响,区间内部任何一子段都不可能同时包含0和1和3(因为总有两个数是作为边界出现的),根据mex的性质,所以他们的mex均与该子段有无3没有关系.
  2. ->对区间外部的和包含这段区间的区间就更没有影响了,因为不管3在区间内部怎么变都不能改变外部不包含3,和包含这段区间的区间一定包含3,3会起作用的一个结果。

为什么只能和比他大交换呢?:

1.比他小的数字作为边界,根据情况1不能动

2:比他小的数字不作为边界,但是之前当做第二种情况可以与比他大的数交换位置算过一次了,避免重复。

综上:

二.代码思路:

设置初始l=pos[0],r=pos[0]

从1~n-1枚举数字。

  1. 若数字没在1~r之间,那么更新边界。
  2. 若数字在l~r之间,那么更新ans=ans*(当前区间长度-已经枚举过的数字数量之和

建议大家自己进行代码实现再来看我的代码,也是可以更好地锻炼代码能力!,也许你写的比我更好呢!也可以给博主提提建议哈!

代码

#include 
#include 
#include 
#include 

using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
int a[N];
map pos;
typedef long long LL;
void solve()
{
    int  n;
    cin>>n;
    pos.clear();
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        pos[a[i]]=i;//记录每个数字的位置
    }
    
    int l=pos[0],r=pos[0];//初始化区间为0的位置
    LL ans=1;//当前初始化为1,因为下面是乘法
    for(int i=1;il&&pos[i]T;
    while (T -- )
    {
        solve();
    }
 
    
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1010467.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号