【考题·枚举】旋转子段(枚举+推导优化)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89183624

题目描述

ZYL有N张牌编号分别为1, 2,……,N。他把这N张牌打乱排成一排,然后他要做一次旋转使得旋转后固定点尽可能多。如果第i个位置的牌的编号为i,我们就称之为固定点。旋转可以被认为是将其中的一个子段旋转180度,这意味着子段的第一张牌和最后一张牌交换位置,以及第二张牌和倒数第二张牌交换位置,等等。写一个程序,找到旋转子段(子段长度可以为1)。

题目大意

有一个序列,需要找到一个子序列并对这一个子序列进行翻转,求 a [ i ] = i ( 1 i ) a[i]=i(1\leq i \leq) 的点的最大值。

题解

我们首先需要找到每一个点i的目标点a[i],显然如果要满足当前条件必须要旋转[i,a[i]]或[a[i],i]的子区间。我们可以知道这一个区间的旋转中心就是重点 i + a [ i ] 2 \frac{i+a[i]}{2} .

显然我们可以一遍得到最原始的答案,要让答案更加优秀,我们一定要枚举若干个旋转中心,因此我们去每一每一个坐标作为旋转中心,考虑以这个点为中心所旋转的长度:使答案改变必须要旋转,有可能旋转一部分也有可能旋转全部,因为在旋转的过程中可能会使本来在正确位置上的点错位。

因此我们枚举的长度是每一个不同的旋转子区间的长度且从小到大枚举,因为从小到大有利于统计区间内满足的对数;例如我们旋转的区间是[L,R],且这是以 L + R 2 \frac{L+R}{2} 为旋转中心的第k个长度,那么当前的答案为: s u m ( 1 , L ) + s u m ( R , n ) + k , s u m ( a , b ) [ a , b ] . sum(1,L)+sum(R,n)+k,sum(a,b)表示区间[a,b]内符合条件的答案.
其中这里的sun可以用前缀和来完成。

代码如下:

#include <bits/stdc++.h>

#define pb push_back

using namespace std;

const int N = 200010;
int n;
int a[N];
int pos[N];
int sum[N];
vector<int>cir[N];

inline int sz(int x)
{
	return cir[x].size();
}

inline int S(int l,int r)
{
	return sum[r]-sum[l-1];
}

inline int read(void)
{
	int s = 0;char c = getchar();
	while (c<'0' || c>'9') c = getchar();
	while (c>='0' && c<='9') s = s*10+c-48,c = getchar();
	return s;
}

int main(void)
{
	freopen("rotate.in","r",stdin);
	freopen("rotate.out","w",stdout);
	n = read();
	for (int i=1;i<=n;++i) 
	{
		a[i] = read();
		pos[a[i]] = i;
		if (a[i] == i) sum[i]=sum[i-1]+1;
		else sum[i]=sum[i-1];
	}
	for (int i=1;i<=n;++i) 
		cir[i+pos[i]].pb(abs(i-pos[i])+1);
	int ans = sum[n];
	for (int i=1;i<=2*n;++i)
	{
		if (sz(i) == 0) continue;
		int cnt = 0;
		int mid = i/2;//旋转中心 
		sort(cir[i].begin(),cir[i].end());//将长度从小到大排序 
		for (int j=0;j<sz(i);++j) 
		{
			int len = cir[i][j],l,r;
			if (i%2 == 0) 
			{
				l = mid-len/2;
				r = mid+len/2;
			}
			if (i%2 == 1)
			{
				l = mid-len/2+1;
				r = mid+len/2;
			}
			cnt ++;//cnt表示以i/2为对称中心的第几组数
			ans = max(ans,cnt+S(1,l-1)+S(r+1,n));
		}
	}
	cout<<ans<<endl;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/89183624