题目:
题意:
有一个长度为
n
n
n的串,定义我们要求的固定点的和的意思是
∑
i
=
1
n
[
a
i
=
i
]
1
\sum_{i=1}^n[a_i=i]1
∑i=1n[ai=i]1
现在我们可以对某一段区间进行旋转操作,问这样之后最大的固定点和能是多少
分析:
我们可以通过枚举每个旋转中心来计算答案
设旋转中心为
m
i
d
mid
mid,区间的左边界是
l
l
l,区间的右边界是
r
r
r,
k
k
k表示区间的长度
那么当前这种情况下整个串的答案是
s
u
m
(
1
,
l
−
1
)
+
s
u
m
(
r
+
1
,
n
)
+
k
(
s
u
m
(
a
,
b
)
表
示
a
到
b
之
间
的
固
定
点
总
数
)
sum(1,l-1)+sum(r+1,n)+k(sum(a,b)表示a到b之间的固定点总数)
sum(1,l−1)+sum(r+1,n)+k(sum(a,b)表示a到b之间的固定点总数)
s
u
m
sum
sum的值我们可以用前缀和来处理
而
k
k
k呢,我们将能以
m
i
d
mid
mid为旋转中心从而达到增加固定点的所有长度放入数组中,然后进行从小到大排序,这样
k
k
k就能实现递增而不存在错误了
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#define LZX Mu
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int max(int x,int y) {return x<y?y:x;}
int num[100005],sum[100005];
vector<int> v[200005];
int main()
{
// freopen("rotate.in","r",stdin);
// freopen("rotate.out","w",stdout);
int n=read();
for(int i=1;i<=n;i++) {int a=read();num[a]=i;sum[i]=sum[i-1];if(a==i) sum[i]++;}
for(int i=1;i<=n;i++) v[i+num[i]].push_back(abs(i-num[i])+1);
int ans=0;
for(int i=2;i<=2*n;i++)
{
if(!v[i].size()) continue;
int mid=i/2;
sort(v[i].begin(),v[i].end());
for(int j=0;j<(int)v[i].size();j++)
{
int l,r;
if(i&1) l=mid-v[i][j]/2+1,r=mid+v[i][j]/2;
else l=mid-v[i][j]/2,r=mid+v[i][j]/2;
ans=max(ans,j+1+sum[l-1]+sum[n]-sum[r]);
}
}
cout<<ans;
return 0;
}