一开始的错误思路:
考虑每一个数的贡献,一个数a[i],当且仅当它的区间包含a[i] - 1和a[i] + 1,这个数的贡献变成0.
那么可以找到对于每一个数a[i],他的a[i] - 1和a[i] + 1在哪里。然后处理一些细节。
但是这个细节是做不了的。因为有可能它的区间包含了a[i + 1],它再扩展也没贡献,也有可能它的区间包含了a[i + 1],它再扩展还是有贡献。
比如:
第一种:2、然后包含了3,你再枚举4、5、这些进来已经没用。
第二种:5、然后包含了6,你再枚举4、3、这些进来,是有用的。
所以这个思路wa。处理不了。
1
5
1 3 2 4 5
正解是一个逆向思维吧。
先算出所有的答案,然后再减去不符合的。
对于一个长度为n的序列,可能的合法贡献是n-1
那么可以算出所有区间的所有合法贡献ans,然后,比如[1, 2]是不合法的,就要减去包含【1, 2】的区间数量。‘
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 100000 + 20; int pos[maxn]; void work() { int n; scanf("%d", &n); LL ans = 0; for (int i = 1; i <= n; ++i) { int x; scanf("%d", &x); pos[x] = i; ans += 1LL * (i) * (i - 1) / 2; } for (int i = 2; i <= n; ++i) { int mi = min(pos[i], pos[i - 1]); int mx = max(pos[i], pos[i - 1]); ans -= 1LL * mi * (n - mx + 1); } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d", &t); while (t--) work(); return 0; }