题目回顾
思路简析
首先,这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;
}