topcoder srm 710 div1

problem1 link

给定两个长度都为$n$的数组$A,B$,给出一个操作序列将$A$变成$B$。每个操作可以是以下两种之一:(1)选择一个$i,0\leq i <n$且$A_{i} \neq 0$,令$t=A_{i}$,然后置$A_{i}=0$,最后令$i$位置后的连续$t$个位置分别加1。这个是循环的,$n-1$之后是位置$0$。可能有些位置最后增加的值会超过1;(2)选择一个$i,0\leq i <n$且$A_{i} \neq 0$,然后从$i$开始(包括$i$)向前,每个位置的数字减去1,直到一个位置是$0$,然后把刚刚减去的值的和加到这个位置上。

可以看出操作(2)是操作(1)的逆操作。可以先将$A$只使用操作(1)变成除了$A_{0}$外其余位置都是0,$B$也这样操作,操作序列分别为$P,Q$,那么$P$加上$Q$的逆操作就是答案。

problem2 link

https://blog.csdn.net/xyyxyyx/article/details/102505744#antiNim_41

http://makaidong.com/Saurus/18221_5909731.html

 (1)全是1(不包含魔力堆):

如果全是1,那么无论有几堆,先手都是必胜的. 因为如果有奇数个1,那么Alice直接拿掉魔力石子,然后选择改变游戏,那么他还是赢的.如果有偶数个1,那么Alice直接拿掉魔力石子,然后不选择改变游戏,于是他还是赢的。

 (2)不全是1:

anti-nim的先手必胜条件(不考虑多魔法石子): 

i SG为0,且所有石子均为1

ii SG不为0,且存在一堆石子大于1

所以,如果不全是1,且SG为0的话,Alice是必输的,因为他取魔力石子后,仍然无法改变必输的情况

所以现在情况只有不全是1,且SG不为0. 注意到这个时候任何一方如果直接取魔力石子,都是必败的.所以双方应该会保持SG不为0,然后进行对峙

首先考虑所以石子的数量不超过3.那么SG函数的值就只有3个,1,2,3. 当SG为1或3的时候,肯定有一种取法使得SG为2. 而SG为2的最终情况是2附加一个魔力石子,这种情况是必败的. 所以当石子的数量不超过3时,SG=2先手必败,反之必胜

接下来考虑石子的数量超过3,也就是有4和4以上的数.那么SG函数的值可以分成1和超过1的那些情况. 如果当前SG值为1,那么只能把它变成超过1的值,然而对手又可以把它变回到1

我们考虑假设只有1个超过3的数,那么这时候SG值肯定是大于3的. 直接改变这个数,我们可以使得接下来的局面变成SG=2. 也就是说,如果只有1个超过3的数,那么就是先手必胜

那么如果SG值为1,且我们知道存在超过3的数,那么超过3的数的数量必定至少有2个. 也就是说,经过不断地对峙,原来SG值为1的话,现在SG值仍然为1. 但是经过了很多减少,一定会达到这个局面. 即SG值为1,且超过3的数量只有2个

当这2个其中的一个数减到4以下时,就变成了只有1个超过3的数, 即SG->1->3->2(最终结果).也就是说SG如果为1,必定会转化成2,那么SG=1就是必败局面,而其他情况是必胜局面

最后结论就是: 如果有大于3的数,那么SG=1必败; 如果没有,那么SG=2必败

problem3 link

令$T=\frac{m(m-1)}{2}$.表示有 這麼多個二元組$(i,j), 0\leq i<j<m$

計算這樣一個大小爲$2^T$的數組,$f[0],f[1],.., f[2^{T}-1]$.其中$f[i]$表示在一維空間中選出$m$個區間,使得$i$中爲1的那些bit對應的二元組相交的情況有多少種.

每一個區間看作一對匹配的括號.首先枚舉有多少種不同的括號(不同的兩個不完全重合).

比如對於2種不同括號的有五種形狀:

\begin{matrix}
( & &) & & (& &) & & (& & &) & & (&) & & ( &) & & \\
& (& &) & & (&) & & & (&) & & & & (&) & (& &) &
\end{matrix}

前後兩個滿足$L_{1}<L_{2}$或者$L_{1}<=L_{2}, R_{1}<R_{2}$, 以避免重復搜索

然後對於$m$個區間枚舉每個區間屬於哪一種種類的括號. 

有了這個$f$數組之後, 對於$k$維的問題,就是求解$f_{new}[i]=\sum_{j\&k=i}f_{old}[j]f_{old}[k]$這樣一個dp, 重復計算$k$次就行. 這個可以用Fast Walsh Hadamard.

https://codeforces.com/blog/entry/50572

https://blog.csdn.net/zxyoi_dreamer/article/details/100515338

https://www.cnblogs.com/y-clever/p/6875743.html

https://www.bbsmax.com/A/qVdewO1QJP/ 

 

code for problem1

#include <vector>

class ReverseMancala {
 public:
  std::vector<int> findMoves(const std::vector<int> &S,
                             const std::vector<int> &T) {
    auto p = get(S, false);
    auto q = get(T, true);
    std::copy(q.rbegin(), q.rend(), std::back_inserter(p));
    return p;
  }

 private:
  std::vector<int> get(std::vector<int> s, bool tag) {
    int sum = 0;
    int n = static_cast<int>(s.size());
    for (int i = 0; i < n; ++i) {
      sum += s[i];
    }
    std::vector<int> ans;
    while (s[0] != sum) {
      int p = 1;
      while (!s[p]) {
        ++p;
      }
      if (!tag) {
        ans.push_back(p);
      } else {
        ans.push_back((p + s[p]) % n + n);
      }
      int cur = s[p];
      s[p] = 0;
      for (int i = 0; i < cur; ++i) {
        ++s[(p + 1 + i) % n];
      }
    }
    return ans;
  }
};

code for problem2

#include <algorithm>
#include <string>
#include <vector>

class MagicNim {
public:
  std::string findWinner(const std::vector<int> &a) {
    int sg = 0;
    int m = 0;
    for (int x : a) {
      sg ^= x;
      m = std::max(m, x);
    }
    if (m >= 4) {
      return sg == 1 ? "Bob" : "Alice";
    } else {
      return sg == 2 ? "Bob" : "Alice";
    }
  }
};

code for problem3

#include <vector>

class Hyperboxes {
 public:
  int findCount(int n, int m, int k) {
    this->m = m;
    c.resize(m * 2 + 1);
    c[0] = 1;
    for (int i = 1; i <= m * 2; ++i) {
      c[i] = Mul(c[i - 1], n - i + 1);
      c[i] = Mul(c[i], Pow(i, kMod - 2));
    }

    int total = m * (m - 1) / 2;
    int S = 1 << total;
    g.resize(S, 0);
    f.resize(S, 0);
    for (int cur = 1; cur <= m; ++cur) {
      for (auto &e : g) {
        e = 0;
      }
      std::vector<int> visited(m, 0);
      std::vector<std::pair<int, int>> group_and_pos(m * 2);
      std::vector<int> group(m);
      Dfs1(0, -1, cur, &group_and_pos, 0);
      Dfs2(0, cur, &group, &visited);
    }

    for (int i = 1; i < S; i <<= 1) {
      for (int j = 0; j < S; j += i << 1) {
        for (int k = 0; k < i; ++k) {
          f[j + k] = Add(f[j + k], f[i + j + k]);
        }
      }
    }

    for (int i = 0; i < S; ++i) {
      f[i] = Pow(f[i], k);
    }

    for (int i = 1; i < S; i <<= 1) {
      for (int j = 0; j < S; j += i << 1) {
        for (int k = 0; k < i; ++k) {
          f[j + k] = Sub(f[j + k], f[i + j + k]);
        }
      }
    }

    return f[0];
  }

 private:
  int Index(int i, int j, int m) {
    if (i > j) {
      std::swap(i, j);
    }
    int pre = i == 0 ? 0 : (m - 1 + m - i) * i / 2;
    return pre + (j - i - 1);
  }

  int Add(int a, int b) {
    a += b;
    if (a >= kMod) {
      a -= kMod;
    }
    return a;
  }

  int Sub(int a, int b) {
    a -= b;
    if (a < 0) {
      a += kMod;
    }
    return a;
  }

  int Mul(int a, int b) {
    long long la = a;
    return static_cast<int>(la * b % kMod);
  }

  int Pow(int a, int b) {
    long long la = a;
    long long r = 1;
    while (b > 0) {
      if ((b & 1) == 1) {
        r = r * la % kMod;
      }
      la = la * la % kMod;
      b >>= 1;
    }
    return static_cast<int>(r);
  }

  void Dfs1(int cur, int gcnt, int gnum,
            std::vector<std::pair<int, int>> *group, int mask) {
    if (cur == 2 * gnum) {
      std::vector<int> left(m);
      std::vector<int> right(m);
      for (int i = 0; i < 2 * gnum; ++i) {
        const auto &e = group->at(i);
        if (e.first < gnum) {
          left[e.first] = e.second;
        } else {
          right[e.first - gnum] = e.second;
        }
      }
      for (int i = 0; i < gnum; ++i) {
        if (left[i] == right[i]) {
          return;
        }
      }
      for (int i = 0; i < gnum; ++i) {
        for (int j = i + 1; j < gnum; ++j) {
          if (left[i] == left[j] && right[i] >= right[j]) {
            return;
          }
        }
      }
      int st = 0;
      for (int i = 0; i < gnum; ++i)
        for (int j = i + 1; j < gnum; ++j)
          if (right[i] >= left[j]) st |= 1 << Index(i, j, gnum);
      g[st] = Add(g[st], c[gcnt + 1]);
      return;
    }
    auto &e = group->at(cur);
    for (int i = 0; i < gnum; ++i) {
      if ((mask & (1 << i)) != 0) {
        continue;
      }
      e.first = i;
      mask |= 1 << i;
      e.second = gcnt + 1;
      Dfs1(cur + 1, gcnt + 1, gnum, group, mask);
      if (cur && e.first > group->at(cur - 1).first) {
        e.second = gcnt;
        Dfs1(cur + 1, gcnt, gnum, group, mask);
      }
      mask ^= 1 << i;
      break;
    }
    for (int i = 0; i < gnum; ++i) {
      if ((mask & (1 << i)) != 0 && (mask & (1 << (i + gnum))) == 0) {
        e.first = i + gnum;
        mask |= 1 << (i + gnum);
        e.second = gcnt + 1;
        Dfs1(cur + 1, gcnt + 1, gnum, group, mask);
        if (cur && e.first > group->at(cur - 1).first) {
          e.second = gcnt;
          Dfs1(cur + 1, gcnt, gnum, group, mask);
        }
        mask ^= 1 << (i + gnum);
      }
    }
  }

  void Dfs2(int cur, int gnum, std::vector<int> *group,
            std::vector<int> *visited) {
    if (cur == m) {
      for (int i = 0; i < gnum; ++i) {
        if (visited->at(i) == 0) {
          return;
        }
      }
      int total = gnum * (gnum - 1) / 2;
      for (int s = 0; s < (1 << total); ++s) {
        if (g[s] == 0) {
          continue;
        }
        int st = 0;
        for (int i = 0; i < m; ++i) {
          for (int j = i + 1; j < m; ++j) {
            if (group->at(i) == group->at(j) ||
                (s & (1 << Index(group->at(i), group->at(j), gnum)))) {
              st |= 1 << Index(i, j, m);
            }
          }
        }
        f[st] = Add(f[st], g[s]);
      }
      return;
    }
    for (int j = 0; j < gnum; ++j) {
      group->at(cur) = j;
      visited->at(j) += 1;
      Dfs2(cur + 1, gnum, group, visited);
      visited->at(j) -= 1;
    }
  }

  static constexpr int kMod = 998244353;
  int m;
  std::vector<int> c;
  std::vector<int> g;
  std::vector<int> f;
};
posted @ 2017-03-13 21:26  朝拜明天19891101  阅读(333)  评论(0编辑  收藏  举报