bzoj5158 Alice&Bob(拓扑排序+贪心)

传送门
短代码简单题。
题意简述:对于一个序列 X X X,定义其两个伴随序列 a , b a,b a,b a i a_i ai表示以第 i i i个数结尾的最长上升子序列长度, b i b_i bi表示以第 i i i个数开头的最长下降子序列长度,现在给出 a a a序列,问 b b b序列所有数加起来最大值是多少。


思路:首先发现 b b b序列就是把这个序列反过来之后得到的 X ′ X' X a a a序列,因此贪心证明一波可以发现:对于这个需要自己构造的原序列是较大的数越靠前越好
然后可以根据 a a a序列建一些有向边来表示各个位置的大小关系。
考虑证明如下两个性质:

  1. 如果 ∃ a , b \exist a,b a,b满足 a < b , A a = A b a<b,A_a=A_b a<b,Aa=Ab,那么 X a ≥ X b X_a\ge X_b XaXb,证明显然,如果不满足那么 A b ≥ A a + 1 A_b\ge A_a+1 AbAa+1
  2. 如果 ∃ a \exist a a满足 A a ! = 1 A_a!=1 Aa!=1那么之前一定有至少一个 A t = A a − 1 A_t=A_a-1 At=Aa1,考虑到性质1可以知道令离 a a a最近的一个 t t t使得 X t < X a X_t<X_a Xt<Xa,而之前的都不一定是最优的。

现在已经很清楚如何建边了,我们对于每一个 A A A值记一个 p r e pre pre数组表示前一个 A A A出现的位置。
现在对于每个位置 i i i

  1. p r e A i pre_{A_i} preAi有意义,就从 p r e A i pre_{A_i} preAi向自己连一条有向边。
  2. p r e A i − 1 pre_{A_i-1} preAi1有意义,就从自己向 p r e A i − 1 pre_{A_i-1} preAi1连一条有向边。

这样相当于连出来了一个模糊的关系图。
然后考虑让关系更加精确。
我们将这个图拓扑排序排出来最后的大小关系,那么由于较大的数越靠前越好所以我们用堆来维护这个出队顺序,强制让编号小的先出队即可。
然后考试的时候太慌统计答案的时候写错了丢了一个AK(摔
代码:

#include
#define ri register int
using namespace std;
const int N=1e5+5;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
typedef long long ll;
ll ans=0;
vector<int>e[N];
int q[N],hd,tl,f[N],pre[N],du[N],n,tot=0,stk[N],mp[N];
priority_queue<int,vector<int>,greater<int> >S;
int main(){
    memset(pre,-1,sizeof(pre)),n=read(),tot=n+1;
    for(ri i=1,x;i<=n;++i){
        x=read();
        if(~pre[x])e[pre[x]].push_back(i),++du[i];
        if(~pre[x-1])e[i].push_back(pre[x-1]),++du[pre[x-1]];
        pre[x]=i;
    }
    for(ri i=1;i<=n;++i)if(!du[i])S.push(i);
    while(!S.empty()){
        int p=S.top();
        f[p]=--tot,S.pop();
        for(ri i=0,v;i<e[p].size();++i){
            --du[v=e[p][i]];
            if(!du[v])S.push(v);
        }
    }
    reverse(f+1,f+n+1);
    int len=0;
    for(ri i=1,pos;i<=n;++i){
        if(f[i]>mp[len])mp[++len]=f[i],pos=len;
        else mp[pos=lower_bound(mp+1,mp+len+1,f[i])-mp]=f[i];
        ans+=pos;
    }
    cout<<ans;
    return 0;
}

你可能感兴趣的:(#,贪心,#,拓扑排序)