题目大意:
解题思路:
根据题意得:当
a
[
i
]
=
i
a[i]=i
a[i]=i时
i
i
i是固定点
我们设翻转区间为
[
L
,
R
]
[L,R]
[L,R],如果不满足翻转后
L
,
R
L,R
L,R都成为固定点那么我们将区间缩小为
[
L
+
1
,
R
−
1
]
[L+1,R-1]
[L+1,R−1]一定是更优的
且当
a
[
L
]
+
R
=
a
[
R
]
+
L
a[L]+R=a[R]+L
a[L]+R=a[R]+L时
[
L
,
R
]
[L,R]
[L,R]翻转后
L
、
R
L、R
L、R都为固定点
然后我们将
i
i
i存入
v
[
a
[
i
]
+
i
]
(
v
e
c
t
o
r
)
v[a[i]+i](vector)
v[a[i]+i](vector)中意思是以
i
i
i为翻转点时这个点可能会成为固定点(还要考虑翻转区间)
我们按照每个点成为固定点需要翻转的区间排序(从小到大)
枚举每个点然后更新答案就可以了
A c c e p t e d c o d e : Accepted\ code: Accepted code:
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
#define pb push_back
using namespace std;
int n, ans, mid;
int a[100005], sum[100005];
vector <int> v[200005];
bool cmp(int x, int y) {
return abs(x*2 - mid) < abs(y*2 - mid);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
v[a[i]+i].pb(i);
sum[i] = sum[i-1] + (a[i] == i); //处理前缀和求出除翻转区间外本来有的固定点
}
int N = n << 1;
for (int i = 2; i <= N; ++i) { //枚举翻转点
mid = i;
int num = v[i].size();
sort(v[i].begin(), v[i].end(), cmp); //排序
for (int j = 0; j < num; ++j) {
int l = v[i][j], r = i - v[i][j]; //翻转区间
if (l > r) swap(l, r);
ans = max(ans, sum[l-1] + sum[n] - sum[r] + j+1); //更新答案
//j+1是因为我们按照区间大小排序所以当前枚举区间是包括之前区间的要把之前的点算上
}
}
printf("%d", ans);
}