环中环 (Standard IO)

Description

  被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在3秒内解决,可见此题难度之大。
  问题是这样的:n个整数围成一个环,老师要求选出其中的若干数,使得选中的数所组成的环中,两个相邻数的差的绝对值不等于1。在满足这个前提下,问最多能取多少个数。

Input

  第一行一个正整数n,表示有n个数
  第二行n个整数,a1、a2……an 按顺时针方向围成一个环。

Output

  一个正整数,即表示最多能选多少个数。
 
题解
需要发现一个性质。即枚举完起点把环转化成一行后,用dp[i]表示以第i个数结尾最多能选多少个数,那么在求dp[i]时只需要记录dp[1]到dp[i-1]里前3大的数就可以了(显然3个不同数中至少有一个和a[i]的绝对值不等于1)。同理,在枚举起点时也只要枚举前5个不同的数。因此该题复杂度为O(N)。
但本人笨,不会。于是在用LXF的方法做对。
用dp[i]表示以第i个数结尾最多能选多少个数。
那我们只能在dp[1]..d[i-1]的范围中找到一个最大的dp[j],且a[j]是在 0..a[i]-2,a[i],a[i]+2..max的范围中(因为a[i]-1和a[i]+1与a[i]的差的绝对值等于1)。
可以把原队列复制一次在队尾,把数的个数变成n*2,就可以处理环的最后一个数和第一个数是否冲突。
输出时输出max(dp[i]) div 2。
可以用线段树来优化这一过程(范围找最大)。

最后,我在此吐槽一句,后面的方法是水解。因为数据太水。我的代码不能处理(3,3,3,3,6,6,6,2,2,4,4)结果是7,而我的是9。希望大家能告诉我那错了。

代码

type
  arr=record
        nm,w:longint;
      end;
var
  ans,n,m:longint;
  t:array [0..400001] of longint;
  f,h:array [0..200001] of longint;
  a:array [0..200001] of arr;
function max(o,p:longint):longint;
begin
  if o>p then exit(o)
         else exit(p);
end;

function ins(p,x,y,l,r:longint):longint;
var
  mid:longint;
begin
  if (x=l) and (y=r) then exit(t[p]);
  mid:=(l+r) div 2;
  if y<=mid then exit(ins(p*2,x,y,l,mid)) else
    if mid+1<=x then exit(ins(p*2+1,x,y,mid+1,r)) else
      exit(max(ins(p*2,x,mid,l,mid),ins(p*2+1,mid+1,y,mid+1,r)));
end;

procedure count(x,y,l,r,sum:longint);
var
  mid:longint;
begin
  if l=r then
    begin
      t[x]:=max(t[x],sum);
      exit;
    end;
  mid:=(l+r) div 2;
  if y<=mid then count(x*2,y,l,mid,sum)
            else count(x*2+1,y,mid+1,r,sum);
  t[x]:=max(t[x*2],t[x*2+1]);
end;

procedure qsort(l,r:longint);
var
  i,j,mid:longint;
begin
  i:=l; j:=r;
  mid:=a[(l+r) div 2].nm;
  repeat
    while a[i].nm<mid do inc(i);
    while a[j].nm>mid do dec(j);
    if i<=j then
      begin
    a[0]:=a[i]; a[i]:=a[j]; a[j]:=a[0];
    inc(i); dec(j);
      end;
  until i>j;
  if l<j then qsort(l,j);
  if i<r then qsort(i,r);
end;

procedure main;
var
  i,x,y,z:longint;
begin
  fillchar(f,sizeof(f),0);
  for i:=1 to n*2 do
    begin
      if h[i]-2>0 then x:=ins(1,1,h[i]-2,1,m)
                  else x:=0;
      if h[i]+2<m+1 then y:=ins(1,h[i]+2,m,1,m)
            else y:=0;
      z:=ins(1,h[i],h[i],1,m);
      f[i]:=max(max(x,y),z)+1;
      count(1,h[i],1,m,f[i]);
    end;
  ans:=0;
  for i:=1 to n*2 do
    ans:=max(f[i],ans);
end;

procedure init;
var
  i:longint;
begin
  readln(n);
  for i:=1 to n do
    begin
      read(h[i]);
      h[i+n]:=h[i];
    end;
  for i:=1 to n<<1 do
    begin
      a[i].nm:=h[i];
      a[i].w:=i;
    end;
  qsort(1,n*2);
  m:=1;
  h[a[1].w]:=m;
  for i:=2 to n<<1 do
    begin
      if abs(a[i].nm-a[i-1].nm)=1 then inc(m) else
        if a[i].nm<>a[i-1].nm then inc(m,2);
      h[a[i].w]:=m;
    end;
end;

begin
  init;
  main;
  write(ans div 2);
end.
原文地址:https://www.cnblogs.com/zyx-crying/p/9319598.html