本题主要解题方法是:
## 先找出必须要排序的序列,再前和向后扩展。
------------
我们不难知道,最短的选择长度一定是从 a 和 a' 第一个不一样的字符到最后一个不一样的字符,比如:
1 2 3 4 5
1 2 4 3 5
最短的选择就是 3 和 4 。
- 更加具体的证明方法:根据操作只有一种——排序,可以得到只要同一位置有不同的数就必须要进行排序,将二者变为相同。
接下来我们思考排序的性质对我们的选择进行扩大:
- 先考虑向前扩大:
如果添加的数比我们已经选择的那段数中最小值更小,那么添加进去后必然是放在我们序列前的,又因为单调递增的序列在从小到大排序时顺序不会改变,因此我们只需要在选择的序列前面扩展的序列是单调递增,且最大值小于我们选择序列中的最小值即可。
- 再考虑向后扩大:
如果添加的数比我们已经选择的那段数中最大值更大,那么添加进去后必然是放在我们序列后的,因此我们只需要只需要在选择的序列后面扩展的序列是单调递增,且最小值大于我们选择序列中的最大值即可。
另外的直接在求完基础序列后考虑向前向后扩展是会超时的,因此需要在求基础序列的时候求单调增序列。
#include <bits/stdc++.h>
using namespace std;
const int F = 3000000;
int out, len, s, t, flag, n, op, last, k, ml;
int a1[F], a2[F];
void work1()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a1[i];
for (int i = 1; i <= n; i++)
cin >> a2[i];
last = a1[1];
ml = 0;
for (int i = 1; i <= n; i++)
if (!flag)
{
if (a1[i] != a2[i])
{
s = i;
flag = 1;
if (a1[i - 1] <= a2[s])
s -= ml;
}
else
{
if (last <= a1[i])
ml++;
else
ml = 1;
last = a1[i];
}
}
else
{
if (a1[i] != a2[i])
t = i;
} // 求s和向前扩展的序列
k = t + 1;
last = a2[t];
if (k <= n)
while (a1[k] >= last)
{
last = a1[k];
k++;
if (k > n)
break;
}
t = k - 1; // 直接求向后扩展的序列
cout << s << " " << t << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin >> op;
while (op--)
{
work1();
s = t = 0;
flag = 0;
}
return 0;
}