Codeforces Ronda # 669 (Div.2) D. Saltos centrífugos discretos (dp, pila monótona)

Codeforces Ronda # 669 (Div.2) D. Saltos centrífugos discretos (dp, pila monótona)

1407 D Saltos centrífugos discretos

Pregunta: Dadas n alturas de edificios, es necesario saltar de la posición 1 a la posición n. Preguntar el menor número de saltos
Salto legal i -> j i-> jyo ->j :

  1. yo + 1 = j yo + 1 = j yo+1=j
  2. max (ai + 1, ai + 2,..., aj - 1) <min (ai, aj) max (a_ {i + 1}, a_ {i + 2}, ..., a_ {j-1 }) <min (a_ {i}, a_ {j}) m a x ( ai + 1,unai + 2,. . . ,unaj - 1)<m i n ( unyo,unaj)
  3. max (ai + 1, ai + 2,..., aj - 1)> min (ai, aj) max (a_ {i + 1}, a_ {i + 2}, ..., a_ {j-1 })> min (a_ {i}, a_ {j}) m a x ( ai + 1,unai + 2,. . . ,unaj - 1)>m i n ( unyo,unaj)

Idea: En
primer lugar, la pregunta requiere el número mínimo de saltos, y después de que se juzga que el estado óptimo anterior no afecta, la
primera sensación al pensar en dp es usar la pila monótona para encontrar la posición actual jjEl primero a la izquierda en j es mayor o igual / menor o igual que su posición y luego salta, buscando la posición más larga cada vez. El código principal es el siguiente:

for (int i = 1; i <= n; i++)dp[i] = maxn;
	dp[0] = 0; dp[1] = 0;
	for (int i = 1; i <= n; i++) {
    
    
		cin >> a[i];
		//向左找到第一个小于等于他的位置下标,其余位置的h都大于
		while (sma.size() && a[sma.top()] > a[i]) sma.pop();
		if (sma.empty()) maxx[i] = 0;
		else maxx[i] = sma.top();
		sma.push(i);
 		//向左找到第一个大于等于他的位置下标,其余位置的h都小于
		while (smin.size() && a[smin.top()] < a[i])smin.pop();
		if (smin.empty())minn[i] = 0;
		else minn[i] = smin.top();
		smin.push(i);
 
		if (i == 1)continue;
		dp[i] = dp[i - 1] + 1;
		if (minn[i]) dp[i] = min(dp[i], dp[minn[i]] + 1);
		if (maxx[i]) dp[i] = min(dp[i], dp[maxx[i]] + 1);
	}
	cout << dp[n] << endl;

Pero esta idea no es correcta. La solución más larga no es necesariamente la mejor solución cada vez, por lo que siempre es wa5.
De hecho, cuando dp, intente transferir todas las soluciones factibles y finalmente genere dpn dp_ {n}d pnSí, el código es el siguiente

int a[maxn], maxx[maxn], minn[maxn], dp[maxn];//记录当前位置向左,第一个大于等于/小于等于他的下标
stack<int> sma, smin;
int main()
{
    
    
	int ans = maxn;
	int n, tt;
	//int Min = maxn, Max = 0;//记录2-当前位置的最大/最小值
	cin >> n;
	for (int i = 1; i <= n; i++)dp[i] = maxn;
	dp[0] = 0; dp[1] = 0;
	cin >> a[1];
	sma.push(1);
	smin.push(1);
	for (int i = 2; i <= n; i++) {
    
    
		cin >> a[i];
		dp[i] = dp[i - 1] + 1;
		//向左找第一个小于等于i的下标,中间都大于他
		while (sma.size() && a[sma.top()] >= a[i]) {
    
    
			tt = a[sma.top()];
			sma.pop();
			if (a[i] < tt&&sma.size()) dp[i] = min(dp[i], dp[sma.top()] + 1);
		}
		sma.push(i);
		//向左找第一个大于等于i的下标,中间都小于他
		while (smin.size() && a[smin.top()] <= a[i]) {
    
    
			tt = a[smin.top()];
			smin.pop();
			if (a[i] > tt&&smin.size()) dp[i] = min(dp[i], dp[smin.top()] + 1);
		}
		smin.push(i);
	}
	cout << dp[n] << endl;
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_44986601/article/details/108497128
Recomendado
Clasificación