标签:std 最大值 位置 print printf 一个 包含 分析 ==
题意:给你一个数组,问有多少个区间,满足区间中的数构成一个排列。
思路(大佬代码):我们发现,一个排列一定含有1,所以我们不妨从1开始入手计算构成排列的区间个数。对于每个扫描到的1(假设处于位置i),我们向左右分别延伸,直到遇到1或者到了数组边界,延伸的时候,需要处理下左边到i的最大值和右边到i的最大值。处理之后,我们先处理排列的最大值在左端的情况。我们暴力枚举每一个位置,把它作为区间的左端点(L),现在我们去确认右端点(R),首先,右端点必须大于等于i,因为要包含1。我们先让右端点向左移,因为右端点的mx值不能大于等于左端点的,不然相当于mx值出现了两次。并且R - L + 1必须小于等于mx[L],因为mx[L]是当前排列的最大值,也是排列的长度。之后,因为R - L + 1可能小于mx[L],我们需要增大R,直到长度满足要求,或者下一个数已经在L到R之间出现过了。此时,如果长度满足要求,那么就找到了一个符合要求的排列,答案+1。最大值在右端同理。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 300010; int in_LR[maxn];//in_LR == tot :在L,R之间 int a[maxn], mx[maxn]; int main() { int n, tot = 0, L, R, ans = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { if(a[i] != 1) continue; mx[i] = 1; for (int j = i - 1; a[j] != 1 && j >= 1; j--) mx[j] = max(mx[j + 1], a[j]); for (int j = i + 1; j <= n && a[j] != 1; j++) mx[j] = max(mx[j - 1], a[j]); //处理最大值在左半边的情况 tot++; L = i, R = i; while(in_LR[a[L]] != tot && L >= 1) { in_LR[a[L]] = tot;//放入R和L之间 L--; } for (L++; L <= i; in_LR[a[L++]] = tot - 1) { while(R > i && (R - L + 1 > mx[L] || mx[R] >= mx[L])) in_LR[a[R--]] = tot - 1; while(R < n && R - L + 1 < mx[L]) { if(in_LR[a[R + 1]] == tot || a[R + 1] >= mx[L]) break; in_LR[a[++R]] = tot; } if(R - L + 1 == mx[L]) ans++; } //处理最大值在右半边的情况 tot++; L = i, R = i; while(in_LR[a[R]] != tot && R <= n) { in_LR[a[R]] = tot;//放入R和L之间 R++; } for (R--; R > i; in_LR[a[R--]] = tot - 1) { while(L < i && (R - L + 1 > mx[R] || mx[L] >= mx[R])) in_LR[a[L++]] = tot - 1; while(L > 1 && R - L + 1 < mx[R]) { if(in_LR[a[L - 1]] == tot || a[L - 1] >= mx[R]) break; in_LR[a[--L]] = tot; } if(R - L + 1 == mx[R]) ans++; } } printf("%d\n", ans); }
标签:std 最大值 位置 print printf 一个 包含 分析 ==
原文地址:https://www.cnblogs.com/pkgunboat/p/10987079.html