翻转数列
Posted by-w
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了翻转数列相关的知识,希望对你有一定的参考价值。
某个小朋友要题解,那我也就发一份吧(反正自己又一次翻车了 QAQ)
T1题目大意是给你一个数列,你能将其中的一段区间翻转,要求这个区间翻转后,整个数列的数在自己位子上的数最多,例如数字1在1位置上,求这个区间两端元素。(n<=500000)
这道题第一眼就可以看出是一题贪心,枚举每个点或不翻转,肯定是不行的。
那我们通过思考,发现将这个区间一定将某些数翻转到它应该在的位置上,于是可以计算出每个点若是将它翻转到自己应该在的位置所依靠的对称中心
我们对每个翻转中心计数即可,但是发现翻转一个区间后可能会使得一些原来有序的数改变位置,也就是说只要使得序列的扩张是从小到大的(好像说不清楚啊QAQ)
所以根据每一个点我们计算出将它翻转到自己应该在的位置的翻转中心,之后先根据翻转中心排序(这里可能会出现翻转中心在两数之间所以我们不对它除以2)
对于相同的翻转中心我们根据它的区间长度从小到大排序,使得区间从小到大扩张,因为这个区间一定是从上一个更小的区间扩张而来的,所以我们可以直接统计该区间内的价值,
对于区间之外的可以直接前缀和处理
代码在此(风格诡异,敬请谅解)
var
i,j,ans,k,max,l1,mid,n,k1,k2:
longint
;
lw,a,w,sum,last,s:
array
[
0..5000000
]
of
longint
;
procedure
sort1(l,r:
longint
);
var
i,j,x,y:
longint
;
begin
i:=l;
j:=r;
x:=lw[(l+r)
div
2
];
repeat
while
lw[i]<x
do
inc(i);
while
x<lw[j]
do
dec(j);
if
not
(i>j)
then
begin
y:=lw[i]; lw[i]:=lw[j]; lw[j]:=y;
y:=a[i]; a[i]:=a[j]; a[j]:=y;
y:=w[i]; w[i]:=w[j]; w[j]:=y;
inc(i);
j:=j-
1
;
end
;
until
i>j;
if
l<j
then
sort1(l,j);
if
i<r
then
sort1(i,r);
end
;
procedure
sort(l,r:
longint
);
var
i,j,x,y:
longint
;
begin
i:=l;
j:=r;
x:=w[(l+r)
div
2
];
repeat
while
w[i]<x
do
inc(i);
while
x<w[j]
do
dec(j);
if
not
(i>j)
then
begin
y:=a[i]; a[i]:=a[j]; a[j]:=y;
y:=w[i]; w[i]:=w[j]; w[j]:=y;
y:=lw[i]; lw[i]:=lw[j]; lw[j]:=y;
inc(i); j:=j-
1
;
end
;
until
i>j;
if
l<j
then
sort(l,j);
if
i<r
then
sort(i,r);
end
;
procedure
gg;
var
i:
longint
;
begin
for
i:=
1
to
n
do
begin
sum[i]:=sum[i-
1
];
if
a[i]=i
then
sum[i]:=sum[i]+
1
;
end
;
for
i:=n
downto
1
do
begin
last[i]:=last[i+
1
];
if
a[i]=i
then
last[i]:=last[i]+
1
;
end
;
end
;
begin
readln(n);
for
i:=
1
to
n
do
begin
read(a[i]);
mid:=i+a[i];
if
a[i]<=i
then
lw[i]:=a[i]
else
lw[i]:=i;
w[i]:=mid;
s[i]:=a[i];
end
;
gg;
sort(
1
,n);
i:=
1
; l1:=
0
;
while
i<=n
do
begin
inc(l1);
if
(w[i]<>w[i+l1])
or
(i+l1>n)
then
begin
sort1(i,i+l1-
1
); ans:=
0
;
// writeln(i,‘ ‘,i+l1-1);
for
j:=i+l1-
1
downto
i
do
begin
ans:=ans+
1
;
//writeln(j,‘ ‘,ans);
if
ans+sum[lw[j]-
1
]+last[w[j]-lw[j]+
1
]>max
then
begin
max:=ans+sum[lw[j]-
1
]+last[w[j]-lw[j]+
1
];
k1:=lw[j];
k2:=w[j];
end
;
end
;
i:=i+l1; l1:=
0
;
end
;
end
;
{writeln;
for i:=1 to n do
begin
writeln(a[i],‘ ‘,lw[i],‘ ‘,w[i],‘ ‘,sum[i],‘ ‘,i);
end;}
writeln
(s[k1],
‘ ‘
,s[k2-k1]);
end
.
以上是关于翻转数列的主要内容,如果未能解决你的问题,请参考以下文章