Advertisement
dmkozyrev

194_500.cpp

Jun 24th, 2017
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.95 KB | None | 0 0
  1. #include <vector>
  2. #include <iostream>
  3. #include <iomanip>
  4. #include <algorithm>
  5. #include <map>
  6.  
  7. //  Максимальная длина последовательности:
  8. const int MAX_N = 500;
  9.  
  10. //  Константы, используемые для сжатия четырех чисел в один int для экономии памяти:
  11. const int LIMIT = 511;
  12. const int POW2 = 9;
  13.  
  14. //  Функции перевода из сжатого состояния в нормальное и наоборот:
  15. inline int max_to_key(uint8_t max1, uint8_t max2, uint8_t max3);
  16. std::vector<uint8_t> key_to_max (int key);
  17.  
  18. struct State {
  19.    
  20.     uint32_t key; // сжатое состояние, которое хранит в себе позицию четырех максимумов в последовательности
  21.    
  22.     //  Конструктор
  23.     State(uint8_t max1 = 0, uint8_t max2 = 0, uint8_t max3 = 0)
  24.         : key(max_to_key(max1, max2, max3))
  25.     { }
  26.    
  27.     // Получение всех следующих состояний за текущим
  28.     std::vector<State> next_states(int curr_len) const {       
  29.         // Пытаемся вставить новый максимум в последовательность из уже имеющихся четырех максимумов
  30.         // Рассматриваем все возможные варианты
  31.        
  32.         std::vector<State> answer;
  33.        
  34.         auto max = key_to_max(key);
  35.        
  36.         // Пытаемся вставить между нулевым и первым максимумом:
  37.         if ( abs(max[0] - max[1]) == 1 ) {         
  38.             answer.push_back(State(std::max(max[0], max[1]), max[0], max[1]));
  39.             answer.back().shift_right_after_insert();
  40.         }
  41.        
  42.         // Между нулевым и вторым максимумом
  43.         if ( abs(max[0] - max[2]) == 1) {
  44.             answer.push_back(State(std::max(max[0], max[2]), max[0], max[1]));
  45.             answer.back().shift_right_after_insert();
  46.         }
  47.        
  48.         // Между первым и вторым максимумом
  49.         if ( abs(max[1] - max[2]) == 1) {
  50.             answer.push_back(State(std::max(max[1], max[2]), max[0], max[1]));
  51.             answer.back().shift_right_after_insert();
  52.         }
  53.        
  54.         for (int i = 0; i < 3; ++i)
  55.         // После i-го максимума в конец последовательности:
  56.             if (max[i] == curr_len) {
  57.                 answer.push_back(State(curr_len+1, max[0], max[1]));
  58.                 break;
  59.             }
  60.        
  61.         return answer;
  62.     }
  63.    
  64.    
  65.     //  Сдвиг совпадающих позиций вправо на один после добавления нового максимума (чтобы состояние было корректным)
  66.     void shift_right_after_insert() {
  67.         auto max = key_to_max(key);
  68.        
  69.         for (int i = 1; i <= 2; ++i)
  70.             if (max[0] <= max[i])
  71.                 max[i]++;
  72.                
  73.         key = max_to_key(max[0], max[1], max[2]);
  74.     }
  75. };
  76.  
  77. //  Оператор сравнения для контейнера std::map
  78. inline bool operator < (const State & a, const State & b) {
  79.     return a.key < b.key;
  80. }
  81.  
  82. //  Класс для длинной арифметики:
  83. struct Number {
  84.     static const int POW10 = (int)1e9;
  85.     static const int WIDTH = 9;
  86.     std::vector<int> digits;
  87.    
  88.     Number(int n = 0) : digits(1, n) { }
  89.    
  90.     Number(const std::vector<int> & digits) : digits(digits) { }
  91.    
  92.     Number & operator+= (const Number & other);
  93.    
  94.     inline bool is_zero() const;
  95. };
  96.  
  97. std::ostream & operator<< (std::ostream & os, const Number & num);
  98.  
  99. int main() {   
  100.     freopen("output.txt", "wt", stdout);
  101.    
  102. //  Состояние однозначно определяется:
  103. //      - длиной последовательности
  104. //      - позицией первого максимума
  105. //      - позицией второго максимума
  106. //      - позицией третьего максимума
  107. //      - позицией четвертого максимума
  108.  
  109. //  Вектор, в котором будем хранить количество последовательностей для текущего состояния:
  110. //  Чтобы избежать пятимерного вектора, будем хранить состояния в std::map
  111.     std::vector<std::map<State, Number>> count(1+MAX_N);
  112.  
  113. //  Вектор для вычисленных сумм для каждой длины:
  114.     std::vector<Number> sum(1+MAX_N);
  115.    
  116. //  Начальные состояния для последовательности длины 4:
  117.     std::vector<State> start_states = {
  118.         State(4,3,2),
  119.         State(4,2,3),
  120.         State(3,4,2),
  121.         State(3,2,4),
  122.         State(2,3,4),
  123.         State(2,4,3),
  124.     }; 
  125.    
  126. //  Две очереди, в которых будем хранить состояния, которые необходимо посетить на текущей итерации.
  127. //  Очереди будем чередовать.
  128.     std::vector<State> queue1((1+MAX_N)*(1+MAX_N));
  129.     std::vector<State> queue2((1+MAX_N)*(1+MAX_N));
  130.    
  131. //  Начальная длина и конечная длина:
  132.     int len = 4, n = MAX_N;
  133.    
  134. //  Итератор для работы с очередями (изначально идем по первой очереди):
  135.     auto next_queue_it = queue1.begin();
  136.        
  137. //  Вносим все стартовые состояния в очередь, попутно отмечая количество состояний
  138. //  на текущей длине и считаем начальную сумму
  139.     for (auto & st : start_states) {
  140.         count[len][st] = 1;
  141.         *next_queue_it++ = st;
  142.     }
  143.     sum[len] = 6;
  144.    
  145. //  Флаг для чередования очередей:
  146.     bool flag = true;
  147.    
  148. //  Переменная для нахождения практической оценки максимального размера очереди:
  149.     int max_queue_size = 0;
  150.    
  151. //  Цикл по длине очереди (из текущей длины мы переходим в следующую длину):
  152.     for (int len = 4; len < n; ++len) {
  153.         //  Обеспечиваем чередование очередей
  154.         flag = !flag;
  155.        
  156.         //  В зависимости от flag, выбираем очередь для посещения на текущей итерации:       
  157.         auto curr_queue_start = flag ? queue2.begin() : queue1.begin();
  158.         auto curr_queue_finish = next_queue_it;
  159.        
  160.         //  И выбираем очередь для посещения на следующей итерации
  161.         next_queue_it = flag ? queue1.begin() : queue2.begin();
  162.        
  163.         //  Подсчет количества состояний в очереди: (для оценивания)
  164.         int queue_size = 0;
  165.         //  Идем вдоль всех состояний, которые мы внесли в очередь на предыдущей итерации:
  166.         for (auto curr = curr_queue_start; curr != curr_queue_finish; ++curr) {
  167.             //  Получаем все следующие состояния:
  168.             auto next_states = curr->next_states(len);
  169.             ++queue_size;
  170.             //  Если следующих состояний нет, то переходим к следующему элементу:
  171.             if (next_states.empty())
  172.                 continue;
  173.            
  174.             //  Запоминаем текущее количество состояний перед входом во внутренний цикл:
  175.             Number curr_count = count[len][*curr];
  176.            
  177.             //  Цикл по всем возможным переходам:
  178.             for (auto & next : next_states) {              
  179.                 //  Если мы еще не посетили это состояние
  180.                 if (count[len+1][next].is_zero()) // то вносим его в очередь для посещения на следующей итерации
  181.                     *next_queue_it++ = next;
  182.                    
  183.                 //  Увеличиваем количество последовательностей в следующем состоянии
  184.                 //  на количество последовательностей в текущем состоянии:
  185.                 count[len+1][next] += curr_count;
  186.                
  187.                 //  Пересчитываем суммарное количество всех последовательностей следующей длины:
  188.                 sum[len+1] += curr_count;
  189.             }
  190.         }
  191.        
  192.         //  Обновляем текущий максимальный размер в очереди:
  193.         max_queue_size = std::max(max_queue_size, queue_size);
  194.     }
  195.    
  196. //  Выводим максимальный размер в очереди:
  197. //  std::cout << "Max queue size: " << max_queue_size << std::endl;
  198.    
  199. //  Выводим посчитанные ответы:
  200.     for (int i = 4; i <= n; ++i)
  201.         std::cout << std::setw(4) << i << ":\t" << sum[i] << std::endl;
  202.    
  203.     return 0;
  204. }
  205.  
  206. // Вывод в поток для длинного числа:
  207. std::ostream & operator<< (std::ostream & os, const Number & num) {
  208.     os << num.digits.back();
  209.     for (int i = (int) num.digits.size()-2; i >= 0; --i)
  210.         os << std::setw(Number::WIDTH) << std::setfill('0') << num.digits[i];
  211.     return os << std::setfill(' ');
  212. }
  213.  
  214. // Оператор прибавления к числу:
  215. Number & Number::operator += (const Number & other) {
  216.     int carry = 0;
  217.     int s1 = (int) this->digits.size();
  218.     int s2 = (int) other.digits.size();
  219.     for (int i = 0; i < s1 || i < s2 || carry; ++i) {
  220.         int digit1 = i < s1 ? this->digits[i] : 0;
  221.         int digit2 = i < s2 ? other.digits[i] : 0;
  222.         carry += digit1 + digit2;
  223.         int digit = carry % POW10;
  224.         carry /= POW10;
  225.         if (i < s1) {
  226.             digits[i] = digit;
  227.         } else {
  228.             digits.push_back(digit);
  229.         }
  230.     }
  231.     return *this;
  232. }  
  233.    
  234. //  Проверка на равенство нулю:
  235. inline bool Number::is_zero() const {
  236.     return digits.size() == 1 && digits[0] == 0;
  237. }
  238.  
  239. //  Функции перевода из сжатого состояния в нормальное и наоборот:
  240. inline int max_to_key(uint8_t max1, uint8_t max2, uint8_t max3) {
  241.     return max3 + ((max2 + (max1 << POW2)) << POW2);
  242. }
  243.  
  244. std::vector<uint8_t> key_to_max (int key) {
  245.     std::vector<uint8_t> answer(3);
  246.     answer[2] = key & LIMIT;
  247.     key >>= POW2;
  248.     answer[1] = key & LIMIT;
  249.     key >>= POW2;
  250.     answer[0] = key;
  251.     return answer;
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement