[TJOI2014] Alice and Bob

 

     It's a very good thinking question. I thought about it for a long time before I came up with it qwq (I'm so stupid)

     Consider the use of the a[] array, first of all, you can get some properties of yy (let num[i] be the number of the original i-th position, because the title says at least one permutation can satisfy a[], so we assume num [] does not have the same element):

         1. When a[i] == a[j] and i<j, we can get num[i] > num[j] , because if it is the other way around, a[j] is at least a[i] +1'd.

         2. For any a[i], consider all j where a[j] + 1 == a[i], at least one of them must satisfy: num[j] < num[i]; and obviously, because The transitivity of the previous property, so you only need to find the largest j and then let num[j] < num[i], that is to say, each position will have a certain size relationship with the previous position at most.

   

     Then we treat < as an edge, and we can find that the original image becomes a forest. And now our task is: to find a topological sort of the original sequence, so that the reverse lis sum is the largest.

     This does not seem to be very easy. Filling in a number has too many effects.

     However, we must have an idea in our hearts at first: greedy, try to match small numbers in the later positions.

     

     But I had a concern at first: what if a position is very late, but because it must be smaller than a very early position (or its father number is very small), it is delayed and the answer is poor?

     However, after drawing it proved that this situation does not exist!

     It can be found that the i-th layer of the forest is composed of all x with a[x] == i, and each node will connect to the upper layer with the largest number less than its own point, so this ensures a greedy correctness Properties: We start from the imaginary root (0) and take the preorder traversal strategy of taking the largest numbered son each time.

     The correctness of this greed is that the points we pass through before walking a point i are either ancestors of i (presumably smaller than it) or numbered higher than i (the lower-numbered answer is better).

 

     So it's done hhhhhhhh (although the code is very short by me)

 

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn=100005;
vector<int> g[maxn];
int n,m,pre[maxn],A,num[maxn],now,f[maxn],M[maxn];
inline void update(int x,int y){ for(;x<=n;x+=x&-x) f[x]=max(f[x],y);}
inline int query(int x){ int an=0; for(;x;x-=x&-x) an=max(an,f[x]); return an;}
void dfs(int x){ if(x) num[x]=++now; for(int i=g[x].size()-1;i>=0;i--) dfs(g[x][i]);}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&A),g[pre[A-1]].pb(i),pre[A]=i;
	dfs(0); ll ans=0;
	for(int i=n;i;i--) M[i]=query(num[i]-1)+1,update(num[i],M[i]),ans+=(ll)M[i];
	printf("%lld\n",ans);
	return 0;
}

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325020014&siteId=291194637