Задать вопрос
@rexore

Как решить задачку из контеста?

https://new.contest.yandex.ru/contests/80784/problem
Задача B.
Одна из болей в том, что это нужно сделать через связный список. Оно проходит первые два кейса, но рушится на третьем. Посмотреть содержимое кейса к сожалению нельзя.

Нашёл такую идею:

За O(n) предподсчетом строим 4 массива: префикс максимумов, префикс минимумов, суффикс максимумов и суффикс минимумов. В i-ой позиции в префиксных массивах храним максимум/минимум среди всех чисел, лежащих левее i-ого индекса и индекс этого максимума/минимума. В i-ой позиции в суффиксных массивах храним максимум/минимум среди всех чисел, лежащих правее i-ого индекса и индекс этого максимума/минимума.
Далее для поиска минимальной разницы за O(n) проходим по префиксу минимумов и суффиксу максимумов, считаем текущую разницу минимума и максимума и запоминаем у минимальной разницы индексы.
Для поиска максимальной разницы аналогично с префиксом максимумов и суффиксом минимумов.

Мой код:

class DoubleLinkedListNode {
	constructor(value, prev = null, next = null) {
		this.value = value;
		this.prev = prev;
		this.next = next;
	}
}

class DoubleLinkedList {
	constructor(head = null, tail = null) {
		this.head = head;
		this.tail = tail;
	}
	append(value) {
		const newNode = new DoubleLinkedListNode(value);

		if (!this.head) {
			this.head = newNode;
			this.tail = newNode;
			return;
		}

		this.tail.next = newNode;
		newNode.prev = this.tail;
		this.tail = newNode;
	}
	prepend(value) {
		const newNode = new DoubleLinkedListNode(value);

		if (!this.head) {
			this.head = newNode;
			this.tail = newNode;
			return;
		}

		this.head.prev = newNode;
		newNode.next = this.head;
		this.head = newNode;
	}
	findPrefixMax() {
		if (!this.head)
			return null;

		let currentNode = this.head;
		let mx = -Infinity;
		let i = 0;
		let mxIndex = 0;
		const result = new DoubleLinkedList();

		while (currentNode) {
			if (currentNode.value > mx) {
				mx = currentNode.value;
				mxIndex = i;
			}
			currentNode = currentNode.next;
			result.append([mx, mxIndex]);
			i++;
		}

		return result;
	}
	findPrefixMin() {
		if (!this.head)
			return null;

		let currentNode = this.head;
		let mn = Infinity;
		let i = 0;
		let mnIndex = 0;
		const result = new DoubleLinkedList();

		while (currentNode) {
			if (currentNode.value < mn) {
				mn = currentNode.value;
				mnIndex = i;
			}
			currentNode = currentNode.next;
			result.append([mn, mnIndex]);
			i++;
		}

		return result;
	}
	findSuffixMax() {
		if (!this.head)
			return null;

		let currentNode = this.tail;
		let mx = -Infinity;
		let mxIndex = 0;
		const result = new DoubleLinkedList();

		let len = 0, tmp = this.head;
		while (tmp) {
			len++;
			tmp = tmp.next;
		}

		let i = len - 1;

		while (currentNode) {
			if (currentNode.value > mx) {
				mx = currentNode.value;
				mxIndex = i;
			}

			result.prepend([mx, mxIndex])
			currentNode = currentNode.prev;
			i--;
		}
		return result;
	}
	findSuffixMin() {
		if (!this.head)
			return null;

		let currentNode = this.tail;
		let mn = Infinity;
		let mnIndex = 0;
		const result = new DoubleLinkedList();

		let len = 0, tmp = this.head;
		while (tmp) {
			len++;
			tmp = tmp.next;
		}

		let i = len - 1;

		while (currentNode) {
			if (currentNode.value < mn) {
				mn = currentNode.value;
				mnIndex = i;
			}

			result.prepend([mn, mnIndex])
			currentNode = currentNode.prev;
			i--;
		}
		return result;
	}
	findDifference() {
		const prefixMx = this.findPrefixMax();
		const suffixMx = this.findSuffixMin();

		let mx = -Infinity;
		let mxIndex = 0;
		let currnetNodeStartMx = prefixMx.head;
		let currnetNodeEndMx = suffixMx.head;

		while (currnetNodeStartMx) {

			if ((currnetNodeStartMx.value[0] - currnetNodeEndMx.value[0]) > mx) {
				mx = currnetNodeStartMx.value[0] - currnetNodeEndMx.value[0];
				mxIndex = [currnetNodeStartMx.value[1] + 1, currnetNodeEndMx.value[1] + 1]
			}

			currnetNodeStartMx = currnetNodeStartMx.next
			currnetNodeEndMx = currnetNodeEndMx.next
		}

		const prefixMn = this.findPrefixMin();
		const suffixMn = this.findSuffixMax();

		let mn = Infinity;
		let mnIndex = 0;
		let currnetNodeStartMn = prefixMn.head;
		let currnetNodeEndMn = suffixMn.head;

		while (currnetNodeStartMn) {

			if ((currnetNodeStartMn.value[0] - currnetNodeEndMn.value[0]) < mn) {
				mn = currnetNodeStartMn.value[0] - currnetNodeEndMn.value[0];
				mnIndex = [currnetNodeStartMn.value[1] + 1, currnetNodeEndMn.value[1] + 1]
			}

			currnetNodeStartMn = currnetNodeStartMn.next
			currnetNodeEndMn = currnetNodeEndMn.next
		}


		return [mnIndex, mxIndex];
	}
	toArray() {
		const arr = [];
		let current = this.head;
		while (current) {
			arr.push(current.value);
			current = current.next;
		}
		return arr;
	}
}

function fromArrayToDoubleLinkedList(arr) {
	const doubleLinkedList = new DoubleLinkedList();
	for (let i = 0; i < arr.length; i++) {
		doubleLinkedList.append(arr[i])
	}
	return doubleLinkedList;
}

const fs = require('fs')
let fileContent = fs.readFileSync("input.txt", "utf8");

let arrNums = fileContent.split('\n').map((value) => value.split(' ').map(Number))

const nums = fromArrayToDoubleLinkedList(arrNums[1])

const result = nums.findDifference().map((arr) => arr.join(' ')).join('\n')

fs.writeFileSync("output.txt", result.toString())
  • Вопрос задан
  • 104 просмотра
Подписаться 1 Средний 1 комментарий
Решения вопроса 1
Alexandroppolus
@Alexandroppolus
кодир
Задача B

это которая про две пары индексов, с минимальной и максимальной дельтой?

там нужен просто один цикл по массиву. В нем надо поддерживать наилучшие найденные результаты, а так же максимальный и минимальный элементы слева от текущего. Набросок на js:

function findMM(arr) {
    let minDelta = Infinity, maxDelta = -Infinity;
    let i1 = 0, i2 = 0, j1 = 0; j2 = 0;
    let iMax = 0; // индекс максимального элемента
    let iMin = 0; // индекс минимального элемента
    for (let j = 1; j < arr.length; ++j) {
        //  минимальная дельта - разница между минимальным элементом
        // среди ранее найденных, и текущим
        if (arr[iMin] - arr[j] < minDelta) {
            i1 = iMin;
            j1 = j;
            minDelta = arr[iMin] - arr[j];
        }
        //  максимальная дельта - разница между максимальным элементом
        // среди ранее найденных, и текущим
        if (arr[iMax] - arr[j] > maxDelta) {
            i2 = iMax;
            j2 = j;
            maxDelta = arr[iMax] - arr[j];
        }
        if (arr[j] < arr[iMin]) {
            iMin = j;
        }
        if (arr[j] > arr[iMax]) {
            iMax = j;
        }
    }
    return [[i1, j1], [i2, j2]];
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы