Kaidul

Uva 10909

Dec 1st, 2013
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.71 KB | None | 0 0
  1. /**
  2. You can use a binary search tree to generate the list of luckies.
  3. The tree should be able to remove an element and return k-th smallest element in O(log n) time.
  4.  
  5. Once you have this list, you can solve each test case by bruteforcing L1, starting from L1 = floor(N / 2) and going down to 1.
  6.  
  7. Also note, that no odd number can be represented as a sum of luckies.
  8. **/
  9. #include <bits/stdc++.h>
  10.  
  11. #define Max 666667  /* max. number of nodes in the tree */
  12. #define MaxN 2000001
  13.  
  14. /* Tree's housekeeping...*/
  15. int left[Max], right[Max], parent[Max], key[Max], count[Max], N, root;
  16.  
  17. int Lucky[(MaxN >> 5) + 10];
  18.  
  19. /* Returns the index of the k-th smallest element in the tree. */
  20. int find(int k) {
  21.     for (int x = root;;)
  22.         if (k < count[left[x]])
  23.             x = left[x];
  24.         else if (k == count[left[x]])
  25.             return x;
  26.         else
  27.             k -= count[left[x]] + 1, x = right[x];
  28. }
  29.  
  30. /*
  31.  *  Removes the element with index 'x' from the tree.
  32.  *  Implemented algorithm ensures that the height of the tree does not increase.
  33.  */
  34. void remove(int x) {
  35.     int y;
  36.  
  37.     if (left[x] != 0 and right[x] != 0) {
  38.         if (count[right[x]] >= count[left[x]])
  39.             for (y = right[x]; left[y] != 0; y = left[y]);
  40.         else
  41.             for (y = left[x]; right[y] != 0; y = right[y]);
  42.         key[x] = key[y];
  43.         x = y;
  44.     }
  45.  
  46.     if (left[x] == 0 and right[x] == 0) {
  47.         if (left[parent[x]] == x)
  48.             left[parent[x]] = 0;
  49.         else
  50.             right[parent[x]] = 0;
  51.     } else {
  52.         y = (left[x] == 0) ? right[x] : left[x];
  53.  
  54.         if (parent[x] == 0) {
  55.             parent[root = y] = 0;
  56.             return;
  57.         }
  58.  
  59.         if (left[parent[x]] == x)
  60.             left[parent[x]] = y;
  61.         else
  62.             right[parent[x]] = y;
  63.         parent[y] = parent[x];
  64.     }
  65.  
  66.     for (x = parent[x]; x != 0; x = parent[x])
  67.         count[x]--;
  68. }
  69.  
  70. /* Constructs a balanced tree with b - a + 1 elements; returns index of its root.
  71.    The tree's nodes will get consecutive indices in their order in the tree. */
  72. int build(int a, int b) {
  73.     if (a > b) return 0;
  74.     if (a == b) {
  75.         N++; left[N] = right[N] = 0;
  76.         count[N] = 1;
  77.         return N;
  78.     }
  79.     int c = (a + b) / 2;
  80.     int t = build(a, c - 1);
  81.     left[++N] = t;
  82.     t = N;
  83.     right[t] = build(c + 1, b);
  84.     count[t] = count[left[t]] + count[right[t]] + 1;
  85.     parent[left[t]] = parent[right[t]] = t;
  86.     return t;
  87. }
  88.  
  89. int Set(int N, int pos){
  90.     return N = N | (1 << pos);
  91. }
  92. bool Check(int N, int pos) {
  93.     return (bool)(N & (1 << pos));
  94. }
  95.  
  96. void mark(int x) {
  97.     for (; x; x = right[x]) {
  98.         Lucky[key[x] >> 5] = Set(Lucky[key[x] >> 5], key[x] & 31);
  99.         mark(left[x]); 
  100.     }
  101. }
  102.  
  103. /* Constructs the list of lucky numbers */
  104. void make() {
  105.     int i, j, k;
  106.  
  107.     /* First off, initialize the tree... */
  108.  
  109.     N = count[0] = 0;
  110.     parent[root = build(0, Max)] = 0;
  111.  
  112.     /*
  113.      *  As an optimization, we start with the tree, containing all numbers
  114.      *  of form 6k+1 and 6k+3 in the range of interest.
  115.      *  These are the numbers, which remain after the first two elimination
  116.      *  rounds.
  117.      */
  118.     for (i = 1, j = 1; i <= Max; j += 6)
  119.         key[i++] = j, key[i++] = j + 2;
  120.  
  121.     /* Now just simulation... */
  122.     for (k = 2; k < count[root]; k++) {
  123.         j = key[find(k)] - 1;
  124.         if (j >= count[root]) break;
  125.  
  126.         for (i = j; i < count[root]; i += j)
  127.             remove(find(i));
  128.     }
  129.  
  130.     /* Finally, mark the remaining numbers in the boolean array lucky[] */
  131.     memset(Lucky, 0, sizeof Lucky);
  132.     mark(root);
  133. }
  134.  
  135. int main(void) {
  136.     int a, n;
  137.  
  138.     for (make(); ~scanf("%d", &n);) {
  139.         a = 0;
  140.         if (n >= 1 and (n & 1) == 0) {
  141.             for (a = n/2; a > 0 and !Check(Lucky[a >> 5], a & 31); a--);
  142.             for (; a > 0; a -= 2)
  143.                 if(Check(Lucky[a >> 5], a & 31) and Check(Lucky[(n - a) >> 5], (n - a) & 31))
  144.                     break;
  145.         }
  146.  
  147.         if (a <= 0)
  148.             printf("%d is not the sum of two luckies!\n", n);
  149.         else
  150.             printf("%d is the sum of %d and %d.\n", n, a, n - a);
  151.     }
  152.     return 0;
  153. }
Advertisement
Add Comment
Please, Sign In to add comment