Advertisement
dmkozyrev

calc_number

Mar 29th, 2015
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.75 KB | None | 0 0
  1. #include <iostream>
  2. #include <cmath>
  3. #include <vector>
  4. #include <stack>
  5. typedef long long i64; // В коде будет слишком много long long, поэтому разумнее определить его как i64
  6. using namespace std;
  7.  
  8. //  Функция решения диофантового уравнения a*x + b*y = c:
  9. bool diophant(i64 a, i64 b, i64 c, i64 &x, i64 &y);
  10. //  Функция поиска идемпотентов в кольце вычетов по модулю n, где n = произведение всех элементов вектора v
  11. vector < i64 > idempotents_from_vector(vector <i64> & v);
  12. //  Функция восстановления искомого числа по k известным остаткам от его деления на k известных взаимно простых числа
  13. i64 calc_number(vector<i64> &idempotents, vector<i64> &v_z, vector<i64> &v_ost);
  14.  
  15. int main(){
  16.     cout << "Input count of pairs [base and ost]: ";
  17.     i64 count;
  18.     cin >> count;
  19.    
  20.     cout << "Input " << count << " pairs [base and ost]: " << endl;
  21.  
  22. //  Вектор v_z хранит все основания колец вычетов , введенные пользователем
  23. //  Вектор v_ost хранит все остатки от сравнения по модулю с соответсвующим основанием кольца вычетов
  24. //  В n записывается произведение всех элементов вектора v_z  
  25.     vector <i64> v_z, v_ost;
  26.     i64 p, ost, n = 1;
  27.     for (int i = 1; i <= count; ++i){
  28.         cin >> p >> ost;
  29.         v_z.push_back(p);
  30.         v_ost.push_back(ost);
  31.         n *= p;
  32.     }
  33.    
  34. //  Вектор idempotents хранит все идемпотенты кольца вычетов с основанием n
  35.     vector <i64> idempotents = idempotents_from_vector(v_z);
  36.  
  37. //  В переменной ans хранится результат выполнения функции calc_number - полученное нами число
  38.     i64 ans = calc_number(idempotents, v_z, v_ost);
  39.    
  40.     cout << endl << "ANSWER: " << ans;
  41.    
  42. //  Раскоментировать этот участок кода, если необходимо выполнять ПРОВЕРКУ найденного числа согласно условию
  43. //  cout << endl << endl << "CHECK THIS: " << endl;
  44. //  for (int i = 0; i < count; ++i){
  45. //      i64 a = v_z.at(i), b = v_ost.at(i);
  46. //      cout << ans << " % " << a << " = " << b << " ";
  47. //      if (ans % a == b) cout << "(true)"; else cout << "(false)";
  48. //      cout << endl;
  49. //  }
  50.  
  51. }
  52.  
  53. bool diophant(i64 a, i64 b, i64 c, i64 &x, i64 &y){
  54. //  Решение диофантового уравнения a*x + b*y = c методом Евклида
  55.     stack < i64 >q;
  56.     i64 r;
  57.     while (a % b != 0)
  58.     {
  59.         r = a % b;
  60.         q.push(a / b);
  61.         a = b;
  62.         b = r;
  63.     }
  64.     if (b != 1)
  65.     {
  66.         return false;
  67.     }
  68.     else
  69.     {
  70.         i64 temp;
  71.         x = 1;
  72.         y = q.top();
  73.         q.pop();
  74.         while (!q.empty())
  75.         {
  76.             temp = x;
  77.             x = -y;
  78.             y = -temp - q.top() * y;
  79.             q.pop();
  80.         }
  81.         x *= c;
  82.         y *= -c;
  83.         return true;
  84.     }
  85. }
  86.  
  87. vector < i64 > idempotents_from_vector(vector <i64> & v){
  88. //  Нахождение идемпотентов в кольце вычетов по модулю n, где n - произведение всех элементов вектора v, состоящего из взаимно простых чисел
  89.     i64 n = 1, m;
  90. //  Вычисление n
  91.     for (auto &i : v) n *= i;
  92. //  Двоичный перебор всех представлений n = a * b , где НОД(a,b) = 1;    
  93.     int c = v.size();
  94.     i64 limit = pow(2, c - 1), a, b, x, y;
  95.     vector < i64 > answer; // Будет хранить найденные идемпотенты
  96. //  Достаточно перебрать всего 2^(c-1) диофантовых уравнений, откуда мы вытащим один идемпотент
  97. //  И для найденного идемпотента х посчитаем 1-х парный идемпотент
  98.     for (i64 i = 1; i < limit; ++i)
  99.     {
  100.         m = i;
  101.         a = b = 1;
  102.         for (i64 j = 0; j < c; ++j)
  103.         {
  104.             if (m % 2 == 1)
  105.                 a *= v[j];
  106.             else
  107.                 b *= v[j];
  108.             m /= 2;
  109.         }
  110.         // Решаем полученное диофантово уравнение a*x + b*y = c
  111.         diophant(a, b, 1, x, y);
  112.         // a*x - один идемпотент
  113.         x *= a;
  114.         // Приводим х к нормальному виду: 0 <= x < n
  115.         while (x < 0) x += n;
  116.         while (x >= n) x -= n;
  117.         // Находим парный к нему идемпотент
  118.         y = n + 1 - x;
  119.         // Кидаем оба идемпотента в вектор
  120.         answer.push_back(x);
  121.         answer.push_back(y);
  122.     }
  123. //  Ну и возвращаем вектор
  124.     return answer;
  125. }
  126.  
  127. i64 calc_number(vector<i64> &idempotents, vector<i64> &v_z, vector<i64> &v_ost){
  128. //  Вектор idempotents хранит все идемпотенты кольца вычетов с основанием n
  129. //  Вектор v_z хранит все основания колец вычетов , введенные пользователем
  130. //  Вектор v_ost хранит все остатки от сравнения по модулю с соответсвующим основанием кольца вычетов
  131.     i64 n = 1, num = 0;
  132. //  Так как мы не передаём n , то посчитаем его как произведение всех элементов вектора v_z 
  133.     for (auto &i : v_z) n *= i;
  134. //  Затем сопоставим каждому j-ому кольцу вычетов v_z[j] i-ый идемпотент кольца вычетов по модулю n 
  135.     for (auto &a : idempotents){
  136.         int t = -1, k = 0;
  137.         bool flag = true;
  138.         for(auto &b : v_z){
  139.             // Ищем единственную возможную единицу в остатке при делении a[i] на b[j] .
  140.             // Все остальные остатки при делении a[i] на b[k], где k != j, должны быть нулями
  141.             if (a % b == 1)
  142.                 if (t != -1){
  143.                     flag = false;
  144.                     break;
  145.                 } else
  146.                     t = k;
  147.             ++k;
  148.         }
  149.         // Если мы нашли соответсвующий идемпотент для v_z[t], то сразу умножаем его на v_ost[t] и прибавляем к искомому числу
  150.         if ( flag ) {
  151.             num += a*v_ost[t];
  152.             if (num >= n) num %= n;
  153.         }
  154.     }
  155. // Возвращаем искомое число
  156.     return num;
  157. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement