Advertisement
Guest User

mauricio

a guest
Oct 19th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.41 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define sc(a) scanf("%d", &a)
  4. #define sc2(a, b) scanf("%d %d", &a, &b)
  5. #define sc3(a, b, c) scanf("%d %d %d", &a, &b, &c)
  6. #define pri(x) printf("%d\n", x)
  7. #define prie(x) printf("%d ", x)
  8. #define mp make_pair
  9. #define pb push_back
  10. #define BUFF ios::sync_with_stdio(false);
  11. #define db(x) cerr << #x << " == " << x << endl;
  12. typedef long long ll;
  13. typedef long double ld;
  14. typedef pair<int, int> ii;
  15. typedef vector<int> vi;
  16. typedef vector<ii> vii;
  17. const int INF = 0x3f3f3f3f;
  18. const ll LINF = 0x3f3f3f3f3f3f3f3fll;
  19. const ld pi = acos(-1);
  20. const int MOD = 30011;
  21. vi divip;
  22. typedef vector<ll> poly;
  23. template <typename T> class Karatsuba {
  24.   typedef typename vector<T>::iterator vTi;
  25.   int cut;
  26.   void convolve_naive(vTi a, vTi b, vTi c, int n) {
  27.     int n2 = n * 2;
  28.     for (int i = 0; i < n2; ++i)
  29.       c[i] = 0;
  30.     for (int i = 0; i < n; ++i)
  31.       for (int j = 0; j < n; ++j)
  32.         c[i + j] += a[i] * b[j];
  33.   }
  34.   void karatsuba(vTi a, vTi b, vTi c, int n) {
  35.     if (n <= cut) {
  36.       convolve_naive(a, b, c, n);
  37.       return;
  38.     }
  39.     int nh = n / 2;
  40.     vTi al = a, ah = a + nh, as = c + nh * 10;
  41.     vTi bl = b, bh = b + nh, bs = c + nh * 11;
  42.     vTi x0 = c, x1 = c + n, x2 = c + n * 2, xh = c + nh;
  43.     for (int i = 0; i < nh; ++i) {
  44.       as[i] = al[i] + ah[i];
  45.       bs[i] = bl[i] + bh[i];
  46.     }
  47.     karatsuba(al, bl, x0, nh);
  48.     karatsuba(ah, bh, x1, nh);
  49.     karatsuba(as, bs, x2, nh);
  50.     for (int i = 0; i < n; ++i)
  51.       x2[i] -= x0[i] + x1[i];
  52.     for (int i = 0; i < n; ++i)
  53.       xh[i] += x2[i];
  54.   }
  55.  
  56. public:
  57.   Karatsuba(int _cut = 1 << 5) : cut(_cut) {}
  58.   vector<T> convolve(vector<T> &_a, vector<T> &_b) {
  59.     vector<T> a = _a, b = _b, c;
  60.     int sz = max(a.size(), b.size()), sz2;
  61.     for (sz2 = 1; sz2 < sz; sz2 *= 2)
  62.       ;
  63.     a.resize(sz2);
  64.     b.resize(sz2);
  65.     c.resize(sz2 * 6);
  66.     karatsuba(a.begin(), b.begin(), c.begin(), sz2);
  67.     c.resize(_a.size() + _b.size() - 1);
  68.     return c;
  69.   }
  70. };
  71.  
  72. vector<ll> convolution(vector<ll> cara1, vector<ll> cara2) {
  73.   Karatsuba<ll> kt;
  74.   return kt.convolve(cara1, cara2);
  75. }
  76. int mapa[200200], remapa[200200];
  77. int P;
  78. poly trad(poly &lista1) {
  79.   poly trad(P, 0);
  80.   trad[0] = 0;
  81.   for (int i = 1; i < P; i++) {
  82.     trad[mapa[i]] = lista1[i];
  83.   }
  84.   return trad;
  85. }
  86. poly retrad(poly &lista1) {
  87.   vector<ll> ret(P, 0);
  88.   for (int i = 1; i < P; i++) {
  89.     ret[remapa[i]] = lista1[i];
  90.   }
  91.   return ret;
  92. }
  93. poly merge_mul(poly lista1, poly lista2) {
  94.   poly cara1 = trad(lista1);
  95.   poly cara2 = trad(lista2);
  96.   ll sumcara2 = 0;
  97.   for (ll x : lista2)
  98.     sumcara2 += x;
  99.   ll sumcara1 = 0;
  100.   for (ll x : lista1)
  101.     sumcara1 += x;
  102.   ll zero = (lista1[0]) * sumcara2;
  103.   ll zero2 = (lista2[0]) * (sumcara1 - lista1[0]);
  104.   zero = (zero + zero2) % MOD;
  105.   poly respi = convolution(cara1, cara2);
  106.   poly vai(P, 0);
  107.   for (int i = 1; i < P; i++) {
  108.     vai[i] = (respi[i] + respi[i + P - 1]) % MOD;
  109.   }
  110.   poly ret = retrad(vai);
  111.   ret[0] = zero;
  112.   return ret;
  113. }
  114. poly merge_add(poly lista1, poly lista2) {
  115.   poly respi = convolution(lista1, lista2);
  116.   poly ret(P, 0);
  117.   for (int i = 0; i < P - 1; i++)
  118.     ret[i] = (respi[i] + respi[i + P]) % MOD;
  119.   ret[P - 1] = respi[P - 1];
  120.   return ret;
  121. }
  122. int powe(int, int, int);
  123. poly merge_pot(poly lista1, int pot) {
  124.   poly cara(P, 0);
  125.   for (int i = 0; i < (int)lista1.size(); i++) {
  126.     int idx = powe(i, pot, P);
  127.     cara[idx] = (lista1[i] + cara[idx]) % MOD;
  128.   }
  129.   return cara;
  130. }
  131.  
  132. struct node {
  133.   char op = ' ';      //  *^+.
  134.   int x = -2;         // se for literal é -1, se for constante é entre 0 e 9
  135.   int l = -1, r = -1; // filho esquerda e direita
  136.   int p;              // pai
  137.   node() { op = ' ', x = -2, l = -1, r = -1; }
  138. };
  139. node tree[410];
  140.  
  141. poly eval(int root) {
  142.   if (tree[root].op == '.') {
  143.     if (tree[root].x == -1) {
  144.       poly num(P, 1);
  145.       return num;
  146.     } else {
  147.       poly num(P, 0);
  148.       assert(tree[root].x >= 0);
  149.       num[tree[root].x % P] = 1;
  150.       return num;
  151.     }
  152.   } else if (tree[root].op == '*') {
  153.     return merge_mul(eval(tree[root].l), eval(tree[root].r));
  154.   } else if (tree[root].op == '+') {
  155.     return merge_add(eval(tree[root].l), eval(tree[root].r));
  156.   } else if (tree[root].op == '^') {
  157.     assert(tree[tree[root].r].x >= 2);
  158.     return merge_pot(eval(tree[root].l), tree[tree[root].r].x);
  159.   } else {
  160.     assert(false);
  161.   }
  162. }
  163.  
  164. void parse(string &s) {
  165.   int tot = 0;
  166.   int curr = 0;
  167.   for (char c : s) {
  168.     if (c == '(') {
  169.       if (tree[curr].l == -1) { // novo filho esquerda
  170.         int nxt = ++tot;
  171.         tree[curr].l = nxt;
  172.         tree[nxt].p = curr;
  173.         curr = nxt;
  174.       } else { // novo filho direita
  175.         int nxt = ++tot;
  176.         tree[curr].r = nxt;
  177.         tree[nxt].p = curr;
  178.         curr = nxt;
  179.       }
  180.     } else if (c == '*' or c == '+' or c == '^') {
  181.       curr = tree[curr].p;
  182.       tree[curr].op = c;
  183.       assert(tree[curr].r == -1);
  184.       int nxt = ++tot;
  185.       tree[curr].r = nxt;
  186.       tree[nxt].p = curr;
  187.       curr = nxt;
  188.  
  189.     } else if (c != ')') {
  190.       int x;
  191.       if (c >= 'a' and c <= 'z')
  192.         x = -1; // variavel
  193.       else
  194.         x = c - '0';
  195.       tree[curr].op = '.';
  196.       tree[curr].x = x;
  197.  
  198.     } else {
  199.       curr = tree[curr].p;
  200.     }
  201.     assert(curr != -1);
  202.     // cout << c << " " << curr << endl;
  203.   }
  204. }
  205. int prim[100100];
  206. int powe(int b, int e, int mod) {
  207.   if (e == 0)
  208.     return 1;
  209.   if (e & 1)
  210.     return (b * (ll)powe(b, e - 1, mod)) % mod;
  211.   int x = powe(b, e / 2, mod);
  212.   return (x * (ll)x) % mod;
  213. }
  214. int testa(int x, int p) {
  215.   for (int y : divip) {
  216.     if (powe(x, (p - 1) / y, p) == 1)
  217.       return 0;
  218.   }
  219.   return 1;
  220. }
  221. int primitive_root(int p) {
  222.   if (p == 2)
  223.     return 1;
  224.   for (int i = 2; i < p; i++) {
  225.     if (testa(i, p))
  226.       return i;
  227.   }
  228.   assert(false);
  229. }
  230. int main() {
  231.   int p;
  232.   cin >> p;
  233.   string s;
  234.   cin >> s;
  235.   parse(s);
  236.   P = p;
  237.   for (int i = 2; i < 100100; i++)
  238.     if (!prim[i])
  239.       for (int j = 2 * i; j < 100100; j += i)
  240.         prim[j] = 1;
  241.  
  242.   for (int i = 2; i <= p; i++) {
  243.     if (!prim[i] and (p - 1) % i == 0) {
  244.       divip.pb(i);
  245.     }
  246.   }
  247.   int root = primitive_root(p);
  248.   set<int> gen;
  249.   for (int i = 1; i < p; i++)
  250.     gen.insert(powe(root, i, p));
  251.   assert(gen.size() == p - 1);
  252.   for (int i = 1; i <= p - 1; i++) {
  253.     mapa[i] = powe(root, i, p);
  254.     remapa[powe(root, i, p)] = i;
  255.   }
  256.   poly coco = eval(0);
  257.   pri((int)coco[0]);
  258. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement