CF1793D题解

题目回顾

思路简析

首先,这TM是个排列,并不是TMD随机数据,害得我TM的想了半天。

吐槽完后,回归正题,看到这个题,我们第一眼的算法的是什么呢,好吧,没有算法,枚举至上!!!但是枚举什么却值得商讨,枚举区间,显然不对,O(n^3)完爆时间复杂度。经过我们一行人辛苦的思考了五分钟,一致决定枚举MEX(以后简称M)的值。这样就成O(n)了,胜利的曙光逐渐出现了啊。可是我们怎么求解答案呢

对于M = 1,答案情况如下

答案就是被两个‘1’隔开的三部分,用等差数列求和公式分块求即可

重要思路

对于M = x ,这段区间的不可能存在x,且1到x - 1的数必须全部出现

我们可以在每一次计算中求出1到i全部出现的最短区间长度为多少

l,r为区间的左右端点。

我们用wz1[i] , wz2[i]两个数组记录两个排列中i这个数的出现位置。

然后就是分类讨论了,自己看!

1:当l<=wz1[i]<=r或l<=wz2[i]<=r时,与重要思路中i不可出现在区间中相对,不可能。

2:当wz1[i] < l && wz2[i] < l时,左端点取值范围为max(wz1[i​],wz2[i]​)。右端点取值范围为[r,n]。方案数为(n−r+1)×(l−max(wz1[i​],wz2[i]​)。

3:wz1[i]和wz2[i]全在区间右侧时:右端点取值范围min(wz1[i​],wz2[i]​),左端点取值范围为【1,l】

方案数为(t1 - r) * l。

4区间被包在中间:左端点取值范围为 (wz1[i],l],右端点取值范围【r,wz2[i]),

方案数为(l-wz1[i])* (wz2[i] - r)

最后别忘了将答案+1因为全选也是答案啊!

AC代码如下

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
long long n , p[N] , q[N] , wz1[N] , wz2[N] ,l , r , t1 , t2 , ans;
int main()
{
	scanf("%lld" , &n);
	for(int i = 1 ; i <= n ; i++)
	{
		scanf("%lld" , &p[i]);
		wz1[p[i]] = i;//记录位置
	}
	for(int i = 1 ; i <= n ; i++)
	{
		scanf("%lld" , &q[i]);
		wz2[q[i]] = i;
	}
	t1 = wz1[1] , t2 = wz2[1];
    if (t1 > t2) swap(t1 , t2);
    l = t1 , r = t2;
    if (1 <= t1 - 1) {
        ans += t1 * (t1 - 1) / 2;
    }
    if (t2 + 1 <= n) {
        ans += (n - t2 + 1) * (n - t2) / 2;
    }
    if (t1 < t2) {
        ans += (t2 - t1 - 1) * (t2 - t1) / 2;
    }//mex == 1;
    for(int mex = 2 ; mex <= n ; mex++)
    {
    	t1 = wz1[mex] , t2 = wz2[mex];
    	if(t1 > t2) swap(t1 , t2);//调整大小
    	if(t1 >= l && t1 <= r || t2 >= l && t2 <= r)
    	{
    		l = min(l , t1);
    		r = max(r , t2);
    		continue;
		}//情况一
		if (t1 < l && t2 < l) {
            ans += (n - r + 1) * (l - t2);
        }//情况二
        if (t1 > r && t2 > r) {
            ans += (t1 - r) * l;
        }//情况三
        if (t1 < l && t2 > r) {
            ans += (l - t1) * (t2 - r);
        }//情况四
        l = min(l , t1);
    	r = max(r , t2);//处理区间大小
	}
	cout << ans + 1 << endl;
	return 0;
}

点点关注,点点赞吧,鼓励一个马上参加中考的初三牲吧
 

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值