Advertisement
Guest User

Untitled

a guest
Nov 22nd, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.46 KB | None | 0 0
  1. #include <vector>
  2. #include <iostream>
  3. #include <fstream>
  4. #include <iomanip>
  5. #include <string>
  6.  
  7.  
  8. using namespace std;
  9.  
  10. #define int long long
  11. vector<pair<int,int>> pq; // в этом списке будут хранится пары p * q
  12. vector<pair<pair<int,int>,int > > pqr; // в этом списке будут хранится тройки p*q *r
  13.  
  14. vector<int> primes; // список простых чисел
  15.  
  16.  
  17. const int border = 10000; // граница до которой хотим генерить числа
  18.  
  19.  
  20. const int maxpow = 5;
  21.  
  22.  
  23. bool is_prime(int n) // функция для проверки числа на простоту
  24. {
  25. for (int i = 2; i*i<=n; i++) // если число делится на какое нибудь число до корня то оно составное
  26. if (n%i==0)
  27. return false;
  28. return true; // если не делится то оно простое
  29. }
  30. void gen_prime() // функция которая находит простые числа
  31. {
  32.  
  33. for (int i = 2; i<border; i++)
  34. if(is_prime(i)) // если число простое добавляем его в список
  35. primes.push_back(i);
  36. }
  37.  
  38. bool cmp(pair<int,int> a, pair<int,int> b) // компоратор для сортировки двоек
  39. {
  40. return a.first*a.second<b.first*b.second;
  41. }
  42. bool cmp2(pair<pair<int,int>,int> a, pair<pair<int,int>,int> b) //компоратор для сортировки троек
  43. {
  44. return a.first.first*a.first.second*a.second<b.first.first*b.first.second*b.second;
  45. }
  46. void gen_pq() // генерируем двойки до нужной границы(до 100)
  47. {
  48. for (int i = 1; i<primes.size(); i++) // пробегаем по всем простым и пытаемся сгенерить двойки
  49. for (int j = i; j<primes.size(); j++)
  50. {
  51. int p = primes[i];
  52. int q = primes[j];
  53.  
  54. if (p*q>=border) // если двойка больше границы то дальше нет смысла смотреть и происходит выход из цикла
  55. break;
  56. else // иначе добавляем в список двоек
  57. pq.push_back({primes[i],primes[j]});
  58. }
  59. sort(pq.begin(),pq.end(),cmp); // сортим двойки
  60. }
  61.  
  62. void gen_pqr()
  63. {
  64. for (int i = 1; i<primes.size(); i++)
  65. for (int j = i; j<primes.size(); j++)
  66. {
  67. int p = primes[i];
  68. int q = primes[j];
  69. int r = primes[j];
  70. if (p*q*r>=border) // если тройка больше границы то дальше нет смысла смотреть и происходит выход из цикла
  71. break;
  72. for (int k = j; k<primes.size(); k++)
  73. {
  74.  
  75. r = primes[k];
  76. if (p*q*r>=border)// если тройка больше границы то дальше нет смысла смотреть и происходит выход из цикла
  77. break;
  78. else // иначе добавляем тройку в список троек
  79. pqr.push_back({{primes[i],primes[j]},primes[k]});
  80. }
  81. }
  82. sort(pqr.begin(),pqr.end(),cmp2); // сортим тройки
  83. }
  84.  
  85. int phi (int n) { // стандартный алгоритм для вычисления функции Эйлера
  86.  
  87. int result = n;
  88. for (int i=2; i*i<=n; ++i)
  89. if (n % i == 0) {
  90. while (n % i == 0)
  91. n /= i;
  92. result -= result / i;
  93. }
  94. if (n > 1)
  95. result -= result / n;
  96. return result;
  97. }
  98.  
  99. vector<int> get_divisors(int n) // функция которая возвращает список делителей числа n
  100. {
  101. vector<int> res;
  102. for (int i = 1; i*i<=n; i++)
  103. {
  104. if (n%i==0) // смотрим если n делится на i
  105. {
  106. res.push_back(i); // то добавляем i в список
  107.  
  108. if (n/i!=i) //здесь мы добавляем вторую пару но смотрим если n/i не равно i то n/i Тоже добавляем в список
  109. res.push_back(n/i); //зачем это делать? например рассмотрим число 16.
  110. // 16 делится на 1 и 16/1!=1
  111. // добавляем 1 и 16
  112. // потом добавляем 2 и 8
  113. // при i = 4 16 делится на 4 поэтому добавим 4 в список
  114. // теперь смотрим 16/i = 16/4 = 4. так как 16/i ==i не добавляем в список а то получится что 4 добавится 2 раза
  115. // то есть для 1 пара 16, для 2 пара 8, для 4 пара 4.
  116. // в итоге в список добавится 1 2 4 8 16, причем 4 только 1 раз
  117. }
  118. }
  119. sort(res.begin(),res.end()); // сортим делители
  120. return res;
  121. }
  122.  
  123.  
  124. vector<int> intersect(vector<int> a, vector<int> b) // стандартный алгоритм для пересечения двух отсортированных списков, который возвращает отсортированное пересечение
  125. {
  126. int i = 0, j = 0;
  127. vector<int> res;
  128. while (i<a.size() && j<b.size())
  129. {
  130. if (a[i]<b[j])
  131. i++;
  132. else
  133. if (a[i]>b[j])
  134. j++;
  135. else
  136. {
  137. res.push_back(a[i]);
  138. i++;
  139. j++;
  140. }
  141. }
  142. return res;
  143. }
  144.  
  145.  
  146. vector<vector<int>> getclasses(vector<int> D) // функция для разбиения множетсва на классы bin()
  147. { // например если в множестве числа {1,2,3,4}
  148. //индекс массив означает на какую максимальную степень двойки делится число
  149. // в bin[0] добавится 1 3, то есть 1 и 3 делятся на 2^0 и не делятся на 2^1
  150. // в bin[1] добавится 2. сюда не добавляем 4 так как 2^1 не максимальная степень на которую делится 4
  151. // в bin[2] добавится 4.
  152. vector<char>used(D.size());
  153. vector<vector<int>>bin(maxpow);
  154. for (int b = maxpow-1; b>=0; b--)
  155. {
  156. for (int i = 0; i<D.size(); i++)
  157. {
  158. if (used[i])
  159. continue;
  160. if ((D[i] & ( (1ll<<b)-1))==0) // это проверка на делимость
  161. {
  162. bin[b].push_back(D[i]);
  163. used[i] = 1;
  164. }
  165. }
  166. }
  167.  
  168. return bin;
  169.  
  170. }
  171.  
  172. int calcpq(int p, int q)// функция для подсчета числа свидетелей для чисел вида n = p*q. тут все делаю как написано в методичке
  173. {
  174.  
  175. vector<int> divP = get_divisors(p-1);
  176.  
  177. vector<int> divQ = get_divisors(q-1);
  178.  
  179. vector<int> D = intersect(divP, divQ);
  180.  
  181.  
  182.  
  183. int s[maxpow];
  184. vector<vector<int>> bin = getclasses(D);
  185. int ans = 0;
  186. for (int i = 0; i<maxpow; i++)
  187. {
  188. s[i] = 0;
  189. for (int j = 0;j<bin[i].size(); j++)
  190. s[i]+=phi(bin[i][j]);
  191.  
  192. ans+=s[i]*s[i];
  193. }
  194. return ans;
  195. }
  196. int calcpqr(int p, int q, int r) // функция для подсчета числа свидетелей для чисел вида n = p*q*r. делаю все так как написано в методичке
  197. {
  198. int n = p*q*r;
  199. vector<int> divP = get_divisors(p-1);
  200. vector<int> divQ = get_divisors(q-1);
  201. vector<int> divR = get_divisors(r-1);
  202.  
  203. divP = intersect(divP, get_divisors(n/p-1));
  204. divQ = intersect(divQ, get_divisors(n/q-1));
  205. divR = intersect(divR, get_divisors(n/r-1));
  206.  
  207. vector<vector<int>> bin1 = getclasses(divP);
  208. vector<vector<int>> bin2 = getclasses(divQ);
  209. vector<vector<int>> bin3 = getclasses(divR);
  210. int ans = 0;
  211.  
  212. for (int i = 0; i<maxpow; i++)
  213. {
  214. int s1 = 0,s2 = 0, s3 = 0;
  215.  
  216. for (int j = 0; j<bin1[i].size(); j++)
  217. s1+=phi(bin1[i][j]);
  218.  
  219. for (int j = 0; j<bin2[i].size(); j++)
  220. s2+=phi(bin2[i][j]);
  221.  
  222. for (int j = 0; j<bin3[i].size(); j++)
  223. s3+=phi(bin3[i][j]);
  224.  
  225. ans+=s1*s2*s3;
  226. }
  227. return ans;
  228. }
  229.  
  230. signed main()
  231. {
  232.  
  233. double starttime = clock();// засекаем время начала работы программы
  234. ofstream cout("output.txt");
  235.  
  236. gen_prime();
  237. gen_pq();
  238. gen_pqr();
  239.  
  240.  
  241. for (auto it:pq) // считаем соотношение для двоек
  242. {
  243. if (it.second!=it.first)
  244. {
  245. int x = calcpq(it.first,it.second);
  246. cout << it.first*it.second << " " ;
  247. cout <<fixed << setprecision(20) << x*1.0 / phi(it.first*it.second) << endl;
  248. }
  249. }
  250.  
  251.  
  252. cout << endl;
  253. for (auto it:pqr) // тут считаем для троек
  254. {
  255. int x = calcpqr(it.first.first,it.first.second,it.second);
  256. cout << it.first.first *it.first.second *it.second << " ";
  257.  
  258. cout <<fixed << setprecision(20) << x*1.0 / phi(it.first.first*it.second*it.first.second) << endl;
  259.  
  260. }
  261. // что значат числа в файле? пусть x - количество свидетелей простоты
  262. // Рабин доказал то что x<=phi(n)/4, где phi(n) - функция Эйлера
  263. // то есть x/phi(n)<=1/4. 1/4 это грубая оценка, которая редко достигается, в файл выводятся реальные оценки то есть x/phi(n)
  264.  
  265. double endtime = clock(); // засекаем когда программа завершила работу
  266. cerr << (endtime-starttime)/CLOCKS_PER_SEC << endl; // считаем сколько секунд отработала программа
  267. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement