#P1451. 第3题-小红的排列
-
1000ms
Tried: 397
Accepted: 72
Difficulty: 7
所属公司 :
科大讯飞
时间 :2023年8月13日
-
算法标签>双指针
第3题-小红的排列
思路:双指针
题目要我们求两个排列的本质不同的子排列(连续的)。
直接计算不好做,正难则反。先求所有可能。然后减去重复的就行。
长度为x的所有子排列个数为x∗(x+1)/2,两个排列一共是x∗(x+1)
接下来的问题就是如何找出两个排列中重复的排列。
假设两个数组分别为a,b,令r表示枚举到了b数组的第r位,l表示a数组中,al=br的位置。然后不断往后比对,并记录长度x,直到比对到不同时,减去相应的值(x∗(x+1)/2)即可。
正确性
排列有一个非常重要的性质是:每个数只出现一次。所以每次找最大的长度,遇到不同就断开。这样一定可以。因为之前考虑过的数在之后一定不会再碰到。所以时间复杂度O(N)
这里塔子哥也提醒大家,不要漏掉题目中的任何一个条件。仔细思考如何利用给的每个条件
c++
#include <iostream>
#include <cstdio>
using namespace std;
#define ll long long
const int maxn=2e5+10;
int n;
int a[maxn],b[maxn];
int ida[maxn],idb[maxn];
ll get(ll x){
return x*(x+1)/2;
}
int main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
ida[a[i]]=i;
}
for(int i=1;i<=n;++i){
cin>>b[i];
idb[b[i]]=i;
}
ll ans=(ll)n*(ll)n+n;
for(int l,r=1,cnt;r<=n;){
l=ida[b[r]];
cnt=0;
while(l<=n&&r<=n&&a[l]==b[r]){
l++;
r++;
cnt++;
}
ans-=get(cnt);
}
cout<<ans;
return 0;
}
java
import java.util.Scanner;
public class Main {
static final int maxn = (int) 2e5 + 10;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] a = new int[maxn];
int[] b = new int[maxn];
int[] ida = new int[maxn];
int[] idb = new int[maxn];
for (int i = 1; i <= n; ++i) {
a[i] = scanner.nextInt();
ida[a[i]] = i;
}
for (int i = 1; i <= n; ++i) {
b[i] = scanner.nextInt();
idb[b[i]] = i;
}
long ans = (long) n * n + n;
int r = 1;
while (r <= n) {
int l = ida[b[r]];
int cnt = 0;
while (l <= n && r <= n && a[l] == b[r]) {
l++;
r++;
cnt++;
}
ans -= get(cnt);
}
System.out.println(ans);
}
static long get(long x) {
return x * (x + 1) / 2;
}
}
python
def get(x):
return x * (x + 1) // 2
def main():
maxn = int(2e5) + 10
n = int(input())
a = [0] * maxn
b = [0] * maxn
ida = [0] * maxn
idb = [0] * maxn
a_input = list(map(int, input().split()))
b_input = list(map(int, input().split()))
for i in range(1, n + 1):
a[i] = a_input[i - 1]
ida[a[i]] = i
for i in range(1, n + 1):
b[i] = b_input[i - 1]
idb[b[i]] = i
ans = n * n + n
r = 1
while r <= n:
l = ida[b[r]]
cnt = 0
while l <= n and r <= n and a[l] == b[r]:
l += 1
r += 1
cnt += 1
ans -= get(cnt)
print(ans)
if __name__ == "__main__":
main()
题目描述
小红有两个长度长度为n的排列,并且想用计算机给他们存起来。
但小红的计算机存储算法很神奇,它只会存储排列的子排列,并且不会存储重复的排列。
他想知道,存储这两个排列需要多少次?
注:排列,指由1~n组成的长度为n的序列,且每个数字仅出现一次。
输入描述
第一行输入一个正整数n,代表排列的长度。 第二行输入n个正整数ai,代表第一个排列。 第三行输入n个正整数bi,代表第二个排列。 1≤n≤2×105
输出描述
计算机存储的次数。
示例1
输入
3
1 2 3
3 2 1
输出
9
说明
第一个排列的子排列有:1、2、3、12、23、123
第二个排列的子排列有:3、2、1、32、21、321
总共存储9次。