51nod 1218 最长递增子序列 V2——LIS+思路(套路)

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1218

自己怎么连这种 喜闻乐见的大水题 都做不出来了……

好像见过的套路,就是求每个位置到它为止的LIS和从它开始的LIS,最后拼起来是ans+1的就在LIS上。

然后试图通过方案数来判断经过该位置的LIS有多少,以判断该位置是不是唯一的。

WA了一次后发现自己的树状数组传参没有-1,求成非严格的了。

还是WA了后面的点。给方案数开了long long后多A了几个点,但还是不能AC。尝试取模,通过的点数和没开long long一样。

然后去看题解。

……

原来只要稍加分析就能得出可从长度的唯一性来判断。自己还是思考太少,动手太匆忙……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e4+15,fx=5,mod=998244353;
int n,m,a[N],tp[N],f[N],len[N],cd[N],ans,cnt[N];
//int g[N],p[N],c[N],prn;
int rdn()
{
  int ret=0,fx=1; char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-') fx=-1; ch=getchar();}
  while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return ret*fx;
}
void upd(int &x){x-=(x>=mod?mod:0);}
void query(int x,int &l/*,int &k*/)
{
  for(;x>0+fx;x-=(x&-x))
    {
      if(f[x]>l)
    {
      l=f[x];
      // k=g[x];
    }
      //      else if(f[x]==l) k+=g[x],upd(k);
    }
}
void add(int x,int l/*,int k*/)
{
  for(;x<=m+fx;x+=(x&-x))
    {
      if(l>f[x])
    {
      f[x]=l;
      // g[x]=k;
    }
      //      else if(l==f[x]) g[x]+=k,upd(g[x]);
    }
}
int main()
{
  n=rdn();
  for(int i=1;i<=n;i++) a[i]=tp[i]=rdn();
  sort(tp+1,tp+n+1); m=unique(tp+1,tp+n+1)-tp-1;
  for(int i=1;i<=n;i++) a[i]=lower_bound(tp+1,tp+n+1,a[i])-tp;
  for(int i=n;i;i--)
    {
      query(m-a[i]+fx,len[i]/*,p[i]*/);//not +1 for yan ge
      //      if(!len[i]) p[i]=1; 
      len[i]++;
      add(m-a[i]+1+fx,len[i]/*,p[i]*/);
      if(len[i]>ans){ans=len[i];/*prn=p[i];*/}
      //      else if(len[i]==ans) prn+=p[i],upd(prn);
    }
  memset(f,0,sizeof f);
  //  memset(g,0,sizeof g);
  for(int i=1;i<=n;i++)
    {
      query(a[i]-1+fx,cd[i]/*,c[i]*/);//a[i]-1!!!
      //      if(!cd[i]) c[i]=1;
      cd[i]++;
      if(len[i]+cd[i]==ans+1)cnt[cd[i]]++;
      add(a[i]+fx,cd[i]/*,c[i]*/);
    }
  printf("A:");
  for(int i=1;i<=n;i++)
    if(len[i]+cd[i]==ans+1&&cnt[cd[i]]>1/*&&(ll)p[i]*c[i]%mod<prn*/)
      printf("%d ",i);
  printf("\n");
  printf("B:");
  for(int i=1;i<=n;i++)
    if(len[i]+cd[i]==ans+1&&cnt[cd[i]]==1/*&&(ll)p[i]*c[i]%mod==prn*/)
      printf("%d ",i);
  printf("\n");
  return 0;
}

 

posted on 2018-09-13 20:40  Narh  阅读(229)  评论(0编辑  收藏  举报

导航