решаю уже закончившийся яндекс контест (тренируюсь для поступления в яндекс ШАД) и у меня затык со второй задачей.
Предоставляю ссылки на полные снимки задачи, чтобы не быть косноязычным.
Собственно алгоритмически код верный, завал получается из-за его неэффективности - 16-й тест не проходит, так как превышен лимит времени 2.086 s (должно быть не больше 2 секунд). Я пробовал задавать разные алгоритмы, из всех мною перепробованных представленный ниже на мой взгляд самый эффективный.
Кратко описать принцип моего алгоритма можно так: я ищу все такие варианты удалить элементы из главной цепи, что никакие два из удаляемых не стоят рядом, попутно вычитая из накопленной суммы соответствующие удаляемым вершинам смежные кратности. В финале каждого варианта вершинного покрытия я просто беру накопленную степень двойки (уже вычисленную по нужному модулю в массиве P) и добавляю её в G.
Собственно, мне по крайней мере интуитивно понятно, что с допустим 100000-элементной цепью со смежной кратностью 100 у каждой вершины моя рекурсия не должна справиться, так как даже если говорить о просто изменении G, то этих изменений колоссальное количество. По-моему тут даже цикловая реализация не поможет.
Так что же всё-таки не так? Может я не вижу какой-то чисто математической фишки? И возможно ли вообще удовлетворить всем требованиям задачи на все (даже крайние-длинные) случаи?
https://ibb.co/LtC97wchttps://ibb.co/Phwc34Mhttps://ibb.co/D7JyGXN
//#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
//#include <cstdlib>
#define Nr 10000001 // размера массива всех возможных степеней двойки по модулю Nm
typedef unsigned int uint;
const uint Nm = 1000000007; // модуль по которому требуется ответ
uint G; //глобальный накопитель
uint sum(uint a, uint b) {
return (a + b) % Nm;
}
void analyze(uint S, uint K, uint L, uint* M, uint* P) { // S - накопленная сумма на данном уровне рекурсии
for (uint i = K + 2; i < L; i++) analyze(S - M[i], i, L, M, P); //K - номер последней дырки
G = sum(G, P[S]);
}
int main() {
uint* P=(uint*)malloc(Nr*sizeof(uint)); // P - массив степеней двойки
P[0] = 1;
for (int i = 1; i < Nr; i++) P[i] = (P[i - 1] << 1) % Nm;
uint L; // L - длина цепи
scanf("%u", &L);
uint* M = (uint*)malloc(L * sizeof(uint)); //M - массив смежных кратностей вершин цепи
for (uint i = 0; i < L; i++) scanf("%u", &M[i]);
uint big = 0; // big - максимально возможная степень двойки
for (uint i = 0; i < L; i++) big += M[i]; // определение big
G = P[big]; // вручную добавляем P[big] к G, чтобы учесть тот случай, когда дырок нет
for (uint i = 0; i < L; i++) analyze(big - M[i], i, L, M, P); // вручную запускаем все варианты того, какая дырка будет первой
printf("%u", G);
free(M);
free(P);
}
i |
Lia: название темы изменено на более содержательное. Большая просьба писать текст задач здесь, хотя бы помимо скринов, а лучше вместо. Наиболее оптимально: текст+ картинка, если она есть в условии. |