[TJOI2014]Alice and Bob[拓撲排序+貪心]
阿新 • • 發佈:2018-10-20
pen arrow 如果 pri 說我 getc ret get bool
題意
給出一個序列的以每一項結尾的 \(LIS\) 的長度a[],求一個序列,使得以每一項為開頭的最長下降子序列的長度之和最大。
\(n\leq 10^5\) 。
分析
最優解一定是一個排列,因為如果兩個數字的大小相同,完全可以區別他們的大小,以得到更多的貢獻。
考慮的 \(a\) 給定的限制,顯然對於所有的相同大小的 \(a\) ,前一項 \(a_{p_1}\) 要大於後一項 \(a_{p_2}\),否則一定會產生更長的上升子序列。連邊\(p_2\rightarrow p_1\)表示 \(p_2\) 的值小於\(p_1\)。
對於 \(i\),找到上一次出現 \(a[i]-1\) 的位置,並連邊 $ {pos}_{a[i]-1}\rightarrow i$ ,表示 \(i\)
然後進行貪心的操作,每次在所有入度為0的點中選擇編號最大的並賦上最小的權值。確定數值之後依次確定 \(b\) 的值就好了。
正確性顯然,因為對於相同的 \(a_x\) 來說我們會優先考慮最靠後的 \(last\),同時靠前的不會向 \(last\) 後邊連邊。
總時間復雜度為 \(O(nlogn)\) ,主要是 \(BIT\) 的復雜度。
代碼
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<cctype> #include<queue> #include<vector> using namespace std; #define fi first #define se second #define mp make_pair #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;++i) #define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to) typedef long long LL; typedef pair<int,int> pii; inline int gi(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();} return x*f; } template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;} template<typename T>inline bool Min(T &a,T b){return a>b?a=b,1:0;} const int N=1e5 + 7; int n,edc; int head[N],ind[N],lst[N],a[N],b[N],f[N]; struct edge{ int last,to; edge(){}edge(int last,int to):last(last),to(to){} }e[N*2]; void Add(int a,int b){ e[++edc]=edge(head[a],b),head[a]=edc; ++ind[b]; } int tr[N]; int lowbit(int x){return x&-x;} void modify(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) Max(tr[i],y);} int query(int x){int res=0;for(int i=x;i;i-=lowbit(i)) Max(res,tr[i]);return res;} priority_queue<int>Q; void topo(){ rep(i,1,n) if(!ind[i]) Q.push(i);int tmp=0; while(!Q.empty()){ int u=Q.top();Q.pop(); b[u]=++tmp; go(u) if(--ind[v]==0) Q.push(v); } } int main(){ n=gi(); rep(i,1,n){ a[i]=gi(); if(lst[a[i]]) Add(i,lst[a[i]]); if(lst[a[i]-1]) Add(lst[a[i]-1],i); lst[a[i]]=i; } topo(); LL ans=0; for(int i=n;i;--i){ f[i]=query(b[i]-1)+1; modify(b[i],f[i]); ans+=f[i]; } printf("%lld\n",ans); return 0; }
[TJOI2014]Alice and Bob[拓撲排序+貪心]