【JZOJ3743】【BZOJ5158】Alice and Bob

description

【JZOJ3743】【BZOJ5158】Alice and Bob_第1张图片


analysis

  • 可以贪心还原出原 x x x序列,且 x x x n n n的排列;易知 a a a由是连续若干段的单调不递减区间拼起来而成

  • 而且每一段区间内差值至多为 1 1 1,大概像这样 1 , 1 , 2 , 2 , 2 , 3 , . . . x , 1 , 1 , 1 , 2 , . . . , y , 1 , . . . 1,1,2,2,2,3,...x,1,1,1,2,...,y,1,... 1,1,2,2,2,3,...x,1,1,1,2,...,y,1,...

  • 对每一段区间来说,前一块中的数都小于后一块中的数;而且每一块中数递减填最优

  • 最后一段的数填越小也越优,考虑限制关系,从 a [ i ] − 1 a[i]-1 a[i]1出现最后的位置 j j j i i i连边,表示 a [ j ] < a [ i ] a[j]a[j]<a[i]形成一棵树

  • 由于前向星连边越晚的越早遍历,便可以确保越后的位置 a a a越小, d f s dfs dfs后时间戳即为 a a a

  • 最后再用一个树状数组求 L I S LIS LIS即可


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include
#include
#include
#define MAXN 100005
#define MAXM MAXN*2
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=las[a];i;i=nex[i])

using namespace std;

ll las[MAXM],nex[MAXM],tov[MAXM];
ll a[MAXN],dfn[MAXN],last[MAXN];
ll tr[MAXN];
ll n,tot,ans;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll lowbit(ll x){return x&(-x);}
inline ll max(ll x,ll y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline void dfs(ll x){dfn[x]=++tot;rep(i,x)dfs(tov[i]);}
inline void link(ll x,ll y){nex[++tot]=las[x],las[x]=tot,tov[tot]=y;}
inline void modify(ll x,ll y){while (x<=n)tr[x]=max(tr[x],y),x+=lowbit(x);}
inline ll query(ll x){ll y=0;while (x)y=max(y,tr[x]),x-=lowbit(x);return y;}
int main()
{
	//freopen("alice.in","r",stdin);
	//freopen("alice.out","w",stdout);
	n=read();
	fo(i,1,n)a[i]=read(),link(last[a[i]-1],i),last[a[i]]=i;
	tot=-1,dfs(0);
	fo(i,1,n)printf("%lld ",dfn[i]);
	printf("\n");
	fd(i,n,1)
	{
		ll tmp=query(dfn[i]-1)+1;
		ans+=tmp,modify(dfn[i],tmp);
	}
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(贪心,树状数组,模拟赛)