codeforces1407D Discrete Centrifugal Jumps

https://codeforces.com/contest/1407/problem/D

mdA题没做出来,吧D过了以后一看cf predictor竟然还能上分,刷牙的时候想着不会fst哪题吧?回来一看这题fst了我透,日常优化常数把人剪没了。

可以发现,我们如果要从i跳到j,那么假设我们当前在i,如果a[i+1]>a[i],那么只能按照一个严格下降子序列转移,否则则是按照一个严格上升子序列转移,

所以用树状数组预处理出每个位置右边离它最近的比他大的nxtup[i]和比他小的nxtd[i],然后一直向右判断能否转移就行了,如果还没更新过或者不如当前转移优就能转移。

 

#include
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,cnt,tot,cas,ans;
int a[maxl],dp[maxl],num[maxl];
int b[maxl],nxtup[maxl],nxtd[maxl];
char s[maxl];

inline void upd(int i,int x)
{
	while(i<=tot)
	{
		b[i]=min(x,b[i]);
		i+=i&-i;
	}
}

inline int qry(int i)
{
	int ret=n+1;
	while(i)
	{
		ret=min(ret,b[i]);
		i-=i&-i;
	}
	return ret;
}

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),num[i]=a[i];
	sort(num+1,num+1+n);
	tot=unique(num+1,num+1+n)-num-1;
	for(int i=1;i<=n;i++)
		a[i]=lower_bound(num+1,num+1+tot,a[i])-num;
	for(int i=0;i<=tot;i++)
		b[i]=n+1;
	int c;
	for(int i=n;i>=1;i--)
	{
		c=a[i];
		nxtd[i]=qry(c-1);
		upd(c,i);
	}
	for(int i=0;i<=tot;i++)
		b[i]=n+1;
	for(int i=n;i>=1;i--)
	{
		c=tot-a[i]+1;
		nxtup[i]=qry(c-1);
		upd(c,i);
	}
}

inline void mainwork()
{
	dp[1]=0;int now,last;
	for(int i=2;i<=n;i++)
		dp[i]=n-1;
	for(int i=1;i<=n-1;i++)
	{
		dp[i+1]=min(dp[i+1],dp[i]+1);
		if(a[i+1]>a[i])
		{
			now=i+1;
			while(nxtd[now]<=n)
			{
				last=now;now=nxtd[now];
				if(dp[now]<=dp[i]+1 || a[last]<=a[i])
					break;
				dp[now]=min(dp[now],dp[i]+1);
			}
		}
		if(a[i+1]=a[i])
					break;
				dp[now]=min(dp[now],dp[i]+1);
			}
		}
	}
}

inline void print()
{
	printf("%d\n",dp[n]);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

你可能感兴趣的:(codeforces1407D Discrete Centrifugal Jumps)