【HDU6602】Longest Subarray

Title effect: a string given sequence, asking the longest substring legitimate long, which must meet the legal substring substring [1, C] is number greater than or equal to K 0

answer:

It is defined as a right end point comprising a point of minimum required range right endpoint

Then initialization can be O (n) calculated at each point a right end point

Defines the minimum interval containing the right end point to a point interval

Different definitions interval when the two leftmost elements of the smallest interval containing interval not simultaneously two different

It is not difficult to think of a legitimate substring, if and only if all the most on the left of different intervals are included in the substring, substring legitimate at this time

Therefore, when there is not difficult to think of an illegal range, the range of this illegal left point as the dividing point, divided into left and right sides recursive operation

So with a divide and conquer approach, start asking substring [1, n] is legitimate, if legal, may be the answer, if not legally, then find all the illegal left point, to divide and conquer as the split point go on

Find illegal left point is the complexity of the bottleneck, we consider it to optimize

Maintenance of a segment tree, the largest segment tree maintenance the right point, and provide the right point point where

Then difficult to think of a time segment tree needs to ask [l, r] to obtain the right to see if the right end point of greater than r, is not greater than legitimate, the value returned by another segment tree is not legal point, which divides the dividing points rule

Taking into account all the same color I just left there with the best, so just put each color leftmost interval when I first joined the tree line, from left to right when strict partition, delete a point to delete point while under color of deleting point of a range of added tree line, so we can guarantee no missing or wrong answers

Because each point will be added and deleted once again, so the time complexity of O (nlogn), this problem can

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define INF 1000000007
using namespace std;
int n,c,k,tans;
int a[100001],nxt[100001],hd[100001];
int minsb[100001];
struct node
{
  int p,minr;
}dat[100001*20];

void pushup(int pos)
{
    if(dat[pos<<1].minr>=dat[pos<<1|1].minr)dat[pos]=dat[pos<<1];
    else dat[pos]=dat[pos<<1|1];
}
void change(int l,int r,int p,int v,int pos)
{
    //printf("%d %d %d\n",l,r,p);
    if(l==r && l==p)
    {
      dat[pos]=(node){p,v};
      return;
    }
    int mid=l+r>>1;
    if(p<=mid)change(l,mid,p,v,pos<<1);
    else change(mid+1,r,p,v,pos<<1|1);
    pushup(pos);
}
node ask(int l,int r,int al,int ar,int pos)
{
    if(l==al && r==ar)return dat[pos];
    int mid=l+r>>1;
    node t1,t2;
    if(ar<=mid)return ask(l,mid,al,ar,pos<<1);
    if(al>mid)return ask(mid+1,r,al,ar,pos<<1|1);
    t1=ask(l,mid,al,mid,pos<<1);
    t2=ask(mid+1,r,mid+1,ar,pos<<1|1);
    if(t1.minr>=t2.minr)return t1;
    else return t2;
}
void work(int l,int r)
{
    //printf("%d %d\n",l,r);
    if(l>r)return;
    node td=ask(1,n,l,r,1);
    //printf("  %d %d\n",td.p,td.minr);
    if(l==r)
    {
      if(td.minr<=r)tans=max(tans,1);
      change(1,n,l,0,1);
      if(nxt[l])change(1,n,nxt[l],minsb[nxt[l]],1);
      return;
    }
    if(td.minr>r)
    {
      work(l,td.p-1);
      change(1,n,td.p,0,1);
      if(nxt[td.p])change(1,n,nxt[td.p],minsb[nxt[td.p]],1);
      work(td.p+1,r);
    }
    else 
    {
      tans=max(tans,r-l+1);
      for(int i=l;i<=r;i++)
      {
        //printf("*%d*  %d\n",i,nxt[i]);
        change(1,n,i,0,1);
        //printf("==-=-=-=-=-=-=\n");
        if(nxt[i])change(1,n,nxt[i],minsb[nxt[i]],1);
      }
      return;
    }
}
void init()
{
    memset(a,0,sizeof(a));
    memset(nxt,0,sizeof(nxt));
    memset(hd,0,sizeof(hd));
    memset(minsb,0,sizeof(minsb));
    for(int i=1;i<=n;i++)change(1,n,i,0,1);
    tans=0;
}
int main()
{
    while(scanf("%d%d%d",&n,&c,&k)!=EOF)
    {
      init();
      for(int i=1;i<=n;i++)scanf("%d",&a[i]);
      for(int i=n;i>0;i--)
      {
        nxt[i]=hd[a[i]];
        hd[a[i]]=i;
      }
      for(int i=1;i<=c;i++)
      {
        int t=hd[i],l=1,j;
        if(!t)continue;
        j=t;
        while(l<k && j)
        {
          j=nxt[j];
          if(j)l++;
        }
        if((!j) || l<k)
        {
          while(t){minsb[t]=INF;t=nxt[t];}
        }
        else
        {
          while(t && j){minsb[t]=j;j=nxt[j];t=nxt[t];}
          while(t){minsb[t]=INF;t=nxt[t];}
        }
      }
      for(int i=1;i<=c;i++)if(hd[i])change(1,n,hd[i],minsb[hd[i]],1);
      work(1,n);
      printf("%d\n",tans);
      //for(int i=1;i<=n;i++)printf("%d ",minsb[i]);
    }
    return 0;
}

心得:考场上很快就想到了区间的做法,但是最后维护线段树时只放最左边的想法一直没有突破导致浪费了一点时间,还需要更加努力啊

Guess you like

Origin www.cnblogs.com/worcher/p/11271000.html