JZOJ 6288. 旋轉子段 【排序】【枚舉】

題目大意:

解題思路:

根據題意得:當a[i]=ia[i]=iii是固定點
我們設翻轉區間爲[L,R][L,R],如果不滿足翻轉後L,RL,R都成爲固定點那麼我們將區間縮小爲[L+1,R1][L+1,R-1]一定是更優的
且當a[L]+R=a[R]+La[L]+R=a[R]+L[L,R][L,R]翻轉後LRL、R都爲固定點
然後我們將ii存入v[a[i]+i](vector)v[a[i]+i](vector)中意思是以ii爲翻轉點時這個點可能會成爲固定點(還要考慮翻轉區間)
我們按照每個點成爲固定點需要翻轉的區間排序(從小到大)
枚舉每個點然後更新答案就可以了

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章