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; }