CodeForces Gym 102055 简要题解

Mischievous Problem Setter

模拟。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n, m;
    cin >> n >> m;
    vector<pair<int, int>> a(n);
    for (int i = 0; i < n; ++i) {
      cin >> a[i].first;
    }
    for (int i = 0; i < n; ++i) {
      cin >> a[i].second;
    }
    sort(a.begin(), a.end());
    int ans = 0;
    while (ans < n && m >= a[ans].second) {
      m -= a[ans++].second;
    }
    cout << "Case " << qq << ": " << ans << "\n";
  }
  return 0;
}

Balance of the Force

建出图,如果图不是二分图,则无解。否则枚举最大值,用堆维护最小值的最大可能值。

#include 

using namespace std;

const int inf = 0x3f3f3f3f;

class heap {
  priority_queue<int, vector<int>, greater<int>> p, q;

 public:
  void push(int x) {
    p.push(x);
  }

  void pop(int x) {
    q.push(x);
  }

  int top() {
    while (!q.empty() && p.top() == q.top()) {
      p.pop();
      q.pop();
    }
    return p.top();
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    for (int i = 0; i < m; ++i) {
      int from, to;
      cin >> from >> to;
      --from;
      --to;
      adj[from].push_back(to);
      adj[to].push_back(from);
    }
    vector<vector<int>> a(n, vector<int>(2));
    for (int i = 0; i < n; ++i) {
      cin >> a[i][0] >> a[i][1];
    }
    bool no_solution = false;
    vector<int> sz(n);
    vector<int> cur(n);
    vector<int> min_id(n);
    vector<int> color(n, -1);
    vector<vector<int>> cnt(n, vector<int>(2));
    vector<vector<int>> minv(n, vector<int>(2, inf));
    heap h;
    for (int i = 0; i < n; ++i) {
      if (color[i] == -1) {
        h.push(cur[i] = -inf);
        queue<int> q;
        color[i] = 0;
        min_id[i] = i;
        ++sz[i];
        q.push(i);
        while (!q.empty()) {
          int x = q.front();
          q.pop();
          minv[i][color[x]] = min(minv[i][color[x]], a[x][0]);
          minv[i][!color[x]] = min(minv[i][!color[x]], a[x][1]);
          for (auto y : adj[x]) {
            if (color[y] == -1) {
              color[y] = !color[x];
              min_id[y] = i;
              ++sz[i];
              q.push(y);
            } else if (color[y] == color[x]) {
              no_solution = true;
              break;
            }
          }
        }
        if (no_solution) {
          break;
        }
      }
    }
    if (no_solution) {
      cout << "Case " << qq << ": IMPOSSIBLE" << "\n";
      continue;
    }
    int ans = inf;
    vector<pair<int, int>> events(n * 2);
    for (int i = 0; i < n; ++i) {
      events[i * 2] = make_pair(a[i][0], i);
      events[i * 2 + 1] = make_pair(a[i][1], i + n);
    }
    sort(events.begin(), events.end());
    for (auto p : events) {
      int x = p.second;
      if (x >= n) {
        x -= n;
        if (++cnt[min_id[x]][!color[x]] == sz[min_id[x]]) {
          h.pop(cur[min_id[x]]);
          cur[min_id[x]] = max(cur[min_id[x]], minv[min_id[x]][!color[x]]);
          h.push(cur[min_id[x]]);
        }
      } else {
        if (++cnt[min_id[x]][color[x]] == sz[min_id[x]]) {
          h.pop(cur[min_id[x]]);
          cur[min_id[x]] = max(cur[min_id[x]], minv[min_id[x]][color[x]]);
          h.push(cur[min_id[x]]);
        }
      }
      ans = min(ans, p.first - h.top());
    }
    cout << "Case " << qq << ": " << ans << "\n";
  }
  return 0;
}

GCD Land

m m m n 2 \frac{n}{2} 2n ,令 m m m 的编号 x x x 为不超过 m m m 的素数的乘积,那么此时只有 m + 1 m+1 m+1 m − 1 m-1 m1 没有连起来;考虑去掉 m m m 以内的最大的两个质数 p , q p, q p,q ,用它们去连 1 1 1 − 1 -1 1 (即 x − 1   m o d   p = 0 , x + 1   m o d   q = 0 x-1\bmod p=0, x+1\bmod q=0 x1modp=0,x+1modq=0 ),此时 m − p , m − q , m + p , m + q m-p, m-q, m+p, m+q mp,mq,m+p,m+q 没有被连起来;注意到我们还没有用大于 m m m 的质数,用这些质数连起来,最后CRT合并即可。这个做法需要特判 n ≤ 38 n\le 38 n38 的数据。

to_multiply = []
table = [-1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2183, 27828, 27827, 87889, 87889, 171053, 171053, 323509, 127373, 323509, 151061, 151061, 151061, 151060, 151059, 151058, 151057, 672540170261, 672540170261, 2101641443861, 2101641443861, 4152621523030]

def inv(a, md):
    b, u, v = md, 0, 1
    while a:
        t = b / a
        a, b = b - t * a, a
        v, u = u - t * v, v
    if u < 0:
        u += md
    return u

def crt(m, a):
    mm, aa = m[0], a[0]
    for i in range(1, len(m)):
        mm, aa = mm * m[i], (aa * m[i] * inv(m[i], mm) + a[i] * mm * inv(mm, m[i])) % (mm * m[i])
    return aa

def multiply_all(l, r):
    if l > r:
        return 1
    elif l == r:
        return to_multiply[l]
    else:
        m = (l + r) / 2
        return multiply_all(l, m) * multiply_all(m + 1, r)

tt = int(raw_input())
for qq in range(1, tt + 1):
    n = int(raw_input())
    if n < 39:
        ans = table[n]
    else:
        prime = [True] * (n + 1)
        for i in range(2, n + 1):
            for j in range(i + i, n + 1, i):
                prime[j] = False
        m = (n + 1) / 2
        to_multiply = []
        for i in range(2, m):
            if prime[i]:
                to_multiply.append(i)
        p, q = to_multiply[-2], to_multiply[-1]
        to_multiply = to_multiply[:-2]
        if m * 2 == n and prime[m]:
            to_multiply.append(m)
        r = []
        for i in range(n - m + 1, n):
            if prime[i]:
                r.append(i)
                if len(r) == 4:
                    break
        ans = crt([multiply_all(0, len(to_multiply) - 1), p, q, r[0], r[1], r[2], r[3]], [0, 1, q - 1, p, r[1] - p, q, r[3] - q]) - m
    print "Case " + str(qq) + ": " + str(ans)

Cube

a x a_x ax 表示父亲已经不能走了, x x x 是第一次经过时的期望答案; b x b_x bx 表示父亲已经不能走了, x x x 是第二次经过时的期望答案; c x c_x cx 表示父亲可以走,在 x x x 子树内先走了一步(没有立刻返回父亲)并在子树内停下来时的期望答案; d x d_x dx 表示父亲可以走,在 x x x 子树内先走了一步(没有立刻返回父亲)并在子树内停下来时的概率; e x e_x ex 表示父亲可以走,在 x x x 子树内先走了一步(没有立刻返回父亲)并走出子树的概率。转移自行脑补。

#include 

using namespace std;

const int md = (int) (1e9 + 7);

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (int) ((long long) x * y % md);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n;
    cin >> n;
    vector<int> v(n);
    for (int i = 0; i < n; ++i) {
      cin >> v[i];
    }
    vector<vector<int>> adj(n);
    for (int i = 0; i < n - 1; ++i) {
      int from, to;
      cin >> from >> to;
      --from;
      --to;
      adj[from].push_back(to);
      adj[to].push_back(from);
    }
    vector<int> invs(n + 1);
    invs[0] = invs[1] = 1;
    for (int i = 2; i <= n; ++i) {
      invs[i] = mul(md - md / i, invs[md % i]);
    }
    vector<int> a(n);
    vector<int> b(n);
    vector<int> c(n);
    vector<int> d(n);
    vector<int> e(n);
    vector<int> g(n);
    function<void(int, int)> dfs = [&](int x, int p) {
      if (p != -1) {
        adj[x].erase(find(adj[x].begin(), adj[x].end(), p));
      }
      if (adj[x].empty()) {
        a[x] = b[x] = v[x];
      } else {
        g[x] = adj[x].size();
        int sum = 0;
        for (auto y : adj[x]) {
          dfs(y, x);
          add(sum, a[y]);
        }
        b[x] = mul(sum, invs[g[x]]);
        for (auto y : adj[x]) {
          add(a[x], mul(c[y], invs[g[x]]));
          add(a[x], mul(((sum - a[y] + b[y]) % md + md) % md, mul(invs[g[y] + 1], mul(invs[g[x]], invs[g[x]]))));
          add(a[x], mul(e[y], mul(g[x] == 1 ? v[x] : mul((sum - a[y] + md) % md, invs[g[x] - 1]), invs[g[x]])));
          add(c[x], mul(c[y], invs[g[x] + 1]));
          add(c[x], mul(((sum - a[y] + b[y]) % md + md) % md, mul(invs[g[y] + 1], mul(invs[g[x] + 1], invs[g[x] + 1]))));
          add(c[x], mul(e[y], mul((sum - a[y] + md) % md, mul(invs[g[x]], invs[g[x] + 1]))));
          add(d[x], mul(d[y], invs[g[x] + 1]));
          add(d[x], mul(g[x], mul(invs[g[y] + 1], mul(invs[g[x] + 1], invs[g[x] + 1]))));
          add(d[x], mul(e[y], mul(g[x] - 1, mul(invs[g[x]], invs[g[x] + 1]))));
        }
        e[x] = 1;
        sub(e[x], d[x]);
        sub(e[x], invs[g[x] + 1]);
      }
    };
    int root;
    cin >> root;
    --root;
    dfs(root, -1);
    cout << "Case " << qq << ": " << a[root] << "\n";
  }
  return 0;
}

Mr. Panda and Cactus

对于一棵树的情况,直接选出 k − 1 k-1 k1 条权值最小的边即可;对于一个环,如果环上颜色不完全相同,则至少要选出两条边。对这个做背包即可。

这个题有点卡空间,可以用哈夫曼树优化合并背包得到更优的空间复杂度。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n, m, k;
    cin >> n >> m >> k;
    vector<int> from(m), to(m), cost(m);
    vector<vector<int>> adj(n);
    for (int i = 0; i < m; ++i) {
      cin >> from[i] >> to[i] >> cost[i];
      --from[i];
      --to[i];
      adj[from[i]].push_back(i);
      adj[to[i]].push_back(i);
    }
    vector<vector<pair<long long, pair<int, int>>>> cycles;
    vector<int> pe(n, -1);
    vector<int> depth(n);
    vector<bool> on(m);
    function<void(int)> dfs = [&](int x) {
      for (auto e : adj[x]) {
        if (e != pe[x]) {
          int y = from[e] + to[e] - x;
          if (!depth[y]) {
            depth[y] = depth[x] + 1;
            pe[y] = e;
            dfs(y);
          } else if (depth[x] < depth[y]) {
            vector<int> edges;
            int z = y;
            while (z != x) {
              edges.push_back(pe[z]);
              on[pe[z]] = true;
              z = from[pe[z]] + to[pe[z]] - z;
            }
            edges.push_back(e);
            on[e] = true;
            sort(edges.begin(), edges.end(), [&](int a, int b) {
              return cost[a] < cost[b];
            });
            cycles.emplace_back();
            cycles.back().emplace_back(cost[edges[0]] + cost[edges[1]], make_pair(edges[0], edges[1]));
            for (int i = 2; i < (int) edges.size(); ++i) {
              cycles.back().emplace_back(cost[edges[i]], make_pair(edges[i], -1));
            }
          }
        }
      }
    };
    int need = k;
    for (int i = 0; i < n; ++i) {
      if (!depth[i]) {
        depth[i] = 1;
        dfs(i);
        --need;
      }
    }
    need = max(need, 0);
    vector<int> edges;
    for (int i = 0; i < m; ++i) {
      if (!on[i]) {
        edges.push_back(i);
      }
    }
    sort(edges.begin(), edges.end(), [&](int a, int b) {
      return cost[a] < cost[b];
    });
    cycles.emplace_back();
    for (auto e : edges) {
      cycles.back().emplace_back(cost[e], make_pair(e, -1));
    }
    vector<vector<long long>> dp(cycles.size());
    for (int i = 0; i < (int) cycles.size(); ++i) {
      long long cur = 0;
      dp[i].push_back(cur);
      for (int j = 0; j < (int) cycles[i].size() && j < need; ++j) {
        cur += cycles[i][j].first;
        dp[i].push_back(cur);
      }
    }
    vector<int> left(cycles.size(), -1), right(cycles.size(), -1);
    set<pair<int, int>> huffman;
    for (int i = 0; i < (int) cycles.size(); ++i) {
      huffman.emplace(dp[i].size(), i);
    }
    while ((int) huffman.size() > 1) {
      int x = huffman.begin()->second;
      huffman.erase(huffman.begin());
      int y = huffman.begin()->second;
      huffman.erase(huffman.begin());
      int z = dp.size();
      dp.push_back(vector<long long>(min((int) dp[x].size() + (int) dp[y].size() - 1, need + 1), 1ll << 60));
      for (int i = 0; i < (int) dp[x].size(); ++i) {
        for (int j = 0; j < (int) dp[y].size(); ++j) {
          if (i + j <= need) {
            dp[z][i + j] = min(dp[z][i + j], dp[x][i] + dp[y][j]);
          }
        }
      }
      left.push_back(x);
      right.push_back(y);
      huffman.emplace(dp[z].size(), z);
    }
    vector<bool> bad(m);
    function<void(int, int)> push = [&](int z, int need) {
      if (!need) {
        return;
      }
      if (z < (int) cycles.size()) {
        for (int i = 0; i < need; ++i) {
          bad[cycles[z][i].second.first] = true;
          if (cycles[z][i].second.second != -1) {
            bad[cycles[z][i].second.second] = true;
          }
        }
      } else {
        int x = left[z];
        int y = right[z];
        for (int i = max(0, need - (int) dp[y].size() + 1); i < (int) dp[x].size() && i <= need; ++i) {
          if (dp[x][i] + dp[y][need - i] == dp[z][need]) {
            push(x, i);
            push(y, need - i);
            return;
          }
        }
      }
    };
    push(dp.size() - 1, need);
    cout << "Case " << qq << ": " << dp.back()[need] << "\n";
    vector<int> ans(n, -1);
    function<void(int, int)> color = [&](int x, int c) {
      ans[x] = c;
      for (auto e : adj[x]) {
        if (!bad[e]) {
          int y = from[e] + to[e] - x;
          if (ans[y] == -1) {
            color(y, c);
          }
        }
      }
    };
    int cur = 0;
    for (int i = 0; i < n; ++i) {
      if (ans[i] == -1) {
        color(i, cur++);
        if (cur == k) {
          cur = 0;
        }
      }
    }
    for (int i = 0; i < n; ++i) {
      if (i) {
        cout << " ";
      }
      cout << ans[i] + 1;
    }
    cout << "\n";
  }
  return 0;
}

Cones

求出V图之后积分即可。

#include 

using namespace std;

typedef double ld;

const ld inf = 1e2;
const ld eps = 1e-9;
const ld pi = acos(-1);

struct point {
  ld x, y;

  point(ld x = 0, ld y = 0): x(x), y(y) {
  }

  point operator + (const point &other) const {
    return point(x + other.x, y + other.y);
  }

  point operator - (const point &other) const {
    return point(x - other.x, y - other.y);
  }

  point operator * (const ld &ratio) const {
    return point(x * ratio, y * ratio);
  }
  
  point operator / (const ld &ratio) const {
    return point(x / ratio, y / ratio);
  }
};

ld dot(point a, point b) {
  return a.x * b.x + a.y * b.y;
}

ld cross(point a, point b) {
  return a.x * b.y - a.y * b.x;
}

ld dist(point a, point b) {
  return sqrt(dot(a - b, a - b));
}

bool on_segment(point p, point a, point b) {
  return dot(a - p, b - p) < -eps;
}

point project(point p, point a, point b) {
  point d = b - a;
  return a + d * (dot(p - a, d) / dot(d, d));
}

vector<point> intersect_circle_line(point p, ld r, point a, point b) {
  point c = project(p, a, b);
  ld d = r * r - dot(c - p, c - p);
  if (d < -eps) {
    return vector<point>();
  } else if (d < eps) {
    return vector<point>(1, c);
  }
  point e = (b - a) / dist(a, b) * sqrt(d);
  return vector<point>{c + e, c - e};
}

vector<vector<point>> voronoi(vector<point> p) {
  int n = (int) p.size();
  vector<vector<point>> ans(n);
  for (int i = 0; i < n; ++i) {
    ans[i].emplace_back(-inf, -inf);
    ans[i].emplace_back(inf, -inf);
    ans[i].emplace_back(inf, inf);
    ans[i].emplace_back(-inf, inf);
    for (int j = 0; j < n; ++j) {
      if (j != i) {
        ld a = p[j].x - p[i].x, b = p[j].y - p[i].y, c = -0.5 * (a * (p[i].x + p[j].x) + b * (p[i].y + p[j].y));
        vector<point> bound;
        ans[i].push_back(ans[i][0]);
        for (int k = 0; k + 1 < (int) ans[i].size(); ++k) {
          ld v = a * ans[i][k].x + b * ans[i][k].y + c;
          if (v < eps) {
            bound.push_back(ans[i][k]);
          }
          ld u = a * ans[i][k + 1].x + b * ans[i][k + 1].y + c;
          if ((v < -eps && u > eps) || (v > eps && u < -eps)) {
            ld aa = ans[i][k + 1].y - ans[i][k].y, bb = ans[i][k].x - ans[i][k + 1].x, cc = -(aa * ans[i][k].x + bb * ans[i][k].y), dd = aa * b - bb * a;
            bound.emplace_back((bb * c - cc * b) / dd, (cc * a - aa * c) / dd);
          }
        }
        swap(ans[i], bound);
      }
    }
  }
  return ans;
}

ld integral(ld a, ld c) {
  ld b = sqrt(c * c - a * a);
  ld all = (1 - c) * a * b;
  ld triangle = 1.0 / 2 * a * (c * b - a * a * log(b + c) + a * a * log(a));
  ld circle = 1.0 / 6 * a * (c * b + a * a * log(b + c) - a * a * log(a));
  return all + triangle + circle;
}

ld solve(point a, point b) {
  ld h = fabs(cross(a, b)) / dist(a, b);
  if (dot(a, b - a) > eps) {
    return integral(h, sqrt(dot(b, b))) - integral(h, sqrt(dot(a, a)));
  } else if (dot(b, a - b) > eps) {
    return integral(h, sqrt(dot(a, a))) - integral(h, sqrt(dot(b, b)));
  } else {
    return integral(h, sqrt(dot(a, a))) + integral(h, sqrt(dot(b, b)));
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cout.setf(ios::fixed);
  cout.precision(15);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n;
    cin >> n;
    vector<point> p(n);
    for (int i = 0; i < n; ++i) {
      cin >> p[i].x >> p[i].y;
    }
    random_shuffle(p.begin(), p.end());
    vector<vector<point>> bound = voronoi(p);
    ld ans = 0;
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < (int) bound[i].size(); ++j) {
        point a = bound[i][j], b = bound[i][(j + 1) % bound[i].size()];
        vector<point> q = intersect_circle_line(p[i], 1, a, b);
        vector<point> new_q;
        new_q.push_back(a);
        for (auto p : q) {
          if (on_segment(p, a, b)) {
            new_q.push_back(p);
          }
        }
        new_q.push_back(b);
        if ((int) new_q.size() == 4 && cross(new_q[1] - p[i], new_q[2] - p[i]) < 0) {
          swap(new_q[1], new_q[2]);
        }
        swap(q, new_q);
        for (int k = 0; k + 1 < (int) q.size(); ++k) {
          point a = q[k], b = q[k + 1];
          if (dist(p[i], a) + dist(p[i], b) < 2 + eps) {
            ans += solve(a - p[i], b - p[i]);
          } else {
            ld angle = atan2(b.y - p[i].y, b.x - p[i].x) - atan2(a.y - p[i].y, a.x - p[i].x);
            if (angle < -eps) {
              angle += pi * 2;
            }
            ans += angle / 3;
          }
        }
      }
    }
    cout << "Case " << qq << ": " << ans / 2 << "\n";
  }
  return 0;
}

Pastoral Life in Stardew Valley

暴力。

#include 

using namespace std;

const int N = (int) 1e5;
const int md = (int) (1e9 + 7);

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (int) ((long long) x * y % md);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  vector<int> foo(N + 1);
  vector<int> bar(N + 1);
  for (int i = 3; i <= N; ++i) {
    foo[i] = foo[i - 1];
    add(foo[i], mul(i - 2, i - 1));
    bar[i] = bar[i - 1];
    add(bar[i], mul(i - 2, mul(i - 1, i - 1)));
  }
  for (int qq = 1; qq <= tt; ++qq) {
    int n, m;
    cin >> n >> m;
    int ans_n = mul(foo[n], n);
    sub(ans_n, bar[n]);
    int ans_m = mul(foo[m], m);
    sub(ans_m, bar[m]);
    cout << "Case " << qq << ": " << mul((md + 1) / 4, mul(ans_n, ans_m)) << "\n";
  }
  return 0;
}

Game on the Tree

d s i ds_i dsi 表示 Panda 的起点到 i i i 的距离, d t i dt_i dti 表示 Sheep 的起点到 i i i 的距离,分几种情况讨论:

  • 如果存在某个关键点 d s i ≤ d t i ds_i\le dt_i dsidti ,则 Panda 赢。
  • 否则两个人一定会在环上绕,如果 Sheep 能在 Panda 到环上之前堵住他,则 Sheep 赢。
  • 否则记 Panda 在环上时两边最近的两个关键点距离为 l , r l, r l,r ,如果 Sheep 能先到达另一个再绕到另一个,则 Sheep 赢。
  • 否则,如果 Sheep 要赢,必须建立一个 Panda 的位置到它的位置的映射,使得它可以堵住 Panda ,用环长判一下即可。
#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n;
    cin >> n;
    vector<vector<int>> adj(n);
    vector<int> deg(n);
    for (int i = 0; i < n; ++i) {
      int from, to;
      cin >> from >> to;
      --from;
      --to;
      adj[from].push_back(to);
      adj[to].push_back(from);
      ++deg[from];
      ++deg[to];
    }
    int m;
    cin >> m;
    vector<int> ed(m);
    for (int i = 0; i < m; ++i) {
      cin >> ed[i];
      --ed[i];
    }
    int s, t;
    cin >> s >> t;
    --s;
    --t;
    vector<bool> tree(n);
    queue<int> q;
    for (int i = 0; i < n; ++i) {
      if (deg[i] <= 1) {
        tree[i] = true;
        q.push(i);
      }
    }
    while (!q.empty()) {
      int x = q.front();
      q.pop();
      for (auto y : adj[x]) {
        if (!tree[y] && --deg[y] <= 1) {
          tree[y] = true;
          q.push(y);
        }
      }
    }
    vector<int> id(n, -1);
    vector<int> cycle;
    for (int i = 0; i < n; ++i) {
      if (!tree[i]) {
        int x = i;
        id[x] = cycle.size();
        cycle.push_back(x);
        while (true) {
          int to = -1;
          for (auto y : adj[x]) {
            if (!tree[y] && id[y] == -1) {
              to = y;
              id[y] = cycle.size();
              cycle.push_back(y);
              break;
            }
          }
          if (to == -1) {
            break;
          }
          x = to;
        }
        break;
      }
    }
    m = cycle.size();
    vector<int> top(n, -1);
    function<void(int, int, int)> dfs = [&](int x, int p, int c) {
      top[x] = c;
      for (auto y : adj[x]) {
        if (tree[y] && y != p) {
          dfs(y, x, c);
        }
      }
    };
    for (int i = 0; i < m; ++i) {
      dfs(cycle[i], -1, i);
    }
    auto bfs = [&](int s) {
      vector<int> dist(n, -1);
      queue<int> q;
      dist[s] = 0;
      q.push(s);
      while (!q.empty()) {
        int x = q.front();
        q.pop();
        for (auto y : adj[x]) {
          if (dist[y] == -1) {
            dist[y] = dist[x] + 1;
            q.push(y);
          }
        }
      }
      return dist;
    };
    vector<int> ds = bfs(s), dt = bfs(t);
    bool win = false;
    for (auto x : ed) {
      if (ds[x] <= dt[x]) {
        win = true;
        break;
      }
    }
    if (win) {
      cout << "Case " << qq << ": Panda" << "\n";
      continue;
    }
    int u = top[s], v = top[t];
    if (ds[cycle[u]] > dt[cycle[u]]) {
      cout << "Case " << qq << ": Sheep" << "\n";
      continue;
    }
    int l = m, r = m;
    for (auto x : ed) {
      if (top[x] != v) {
        l = min(l, (u - top[x] + m) % m);
        r = min(r, (top[x] - u + m) % m);
      }
    }
    if (l == m) {
      cout << "Case " << qq << ": Sheep" << "\n";
      continue;
    }
    int ll = (u - l + m) % m, rr = (u + r) % m, between = min(l + r, m - (l + r));
    if (dt[ll] + between < ds[rr] || dt[rr] + between < ds[ll] || l + r > m - (l + r) + 1) {
      cout << "Case " << qq << ": Sheep" << "\n";
    } else {
      cout << "Case " << qq << ": Panda" << "\n";
    }
  }
  return 0;
}

Cockroaches

拿行最大值和列最大值随便讨论一下就好了。

#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n;
    cin >> n;
    vector<int> x(n), y(n);
    unordered_map<int, int> cx, cy;
    for (int i = 0; i < n; ++i) {
      cin >> x[i] >> y[i];
      ++cx[x[i]];
      ++cy[y[i]];
    }
    int tx = 0, ty = 0, wx = 0, wy = 0;
    for (auto p : cx) {
      if (tx < p.second) {
        tx = p.second;
        wx = 1;
      } else if (tx == p.second) {
        ++wx;
      }
    }
    for (auto p : cy) {
      if (ty < p.second) {
        ty = p.second;
        wy = 1;
      } else if (ty == p.second) {
        ++wy;
      }
    }
    int ans = tx + ty;
    long long ways = (long long) wx * wy;
    for (int i = 0; i < n; ++i) {
      if (cx[x[i]] + cy[y[i]] == ans) {
        --ways;
      }
    }
    if (!ways) {
      --ans;
      ways = (long long) wx * wy;
      for (auto p : cx) {
        if (p.second == tx - 1) {
          ways += wy;
        }
      }
      for (auto p : cy) {
        if (p.second == ty - 1) {
          ways += wx;
        }
      }
      for (int i = 0; i < n; ++i) {
        if (cx[x[i]] + cy[y[i]] == ans) {
          --ways;
        }
      }
    }
    if (ans == 1) {
      ways = n;
    } else if (ans == 2) {
      ways = (long long) n * (n - 1) / 2;
    }
    cout << "Case " << qq << ": " << ans << " " << ways << "\n";
  }
  return 0;
}

Mr. Panda and Sequence Puzzle

因为可以翻转的前缀长度需要递增,所以对于一个可以翻转的位置到下一个位置,有两种方案,二分哈希比较即可。

#include 

using namespace std;

const int md0 = (int) (1e9 + 7);
const int md1 = (int) (1e9 + 9);

inline int inv(int a, int md) {
  int b = md, u = 0, v = 1;
  while (a) {
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  if (u < 0) {
    u += md;
  }
  return u;
}

struct hashv {
  int h0, h1;

  hashv(int h0 = 0, int h1 = 0): h0(h0), h1(h1) {
  }

  hashv operator * (const hashv &x) const {
    return hashv((long long) h0 * x.h0 % md0, (long long) h1 * x.h1 % md1);
  }

  hashv operator + (const hashv &x) const {
    return hashv((h0 + x.h0) % md0, (h1 + x.h1) % md1);
  }

  hashv operator - (const hashv &x) const {
    return hashv((h0 + md0 - x.h0) % md0, (h1 + md1 - x.h1) % md1);
  }

  inline long long get() {
    return (long long) h0 * md1 + h1;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    int n, m;
    cin >> n >> m;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
      cin >> a[i];
    }
    vector<bool> ban(n);
    while (m--) {
      int x;
      cin >> x;
      --x;
      ban[x] = true;
    }
    vector<hashv> p(n * 2);
    vector<hashv> inv_p(n * 2);
    p[0] = inv_p[0] = hashv(1, 1);
    hashv base(2333, 2333);
    hashv inv_base(inv(2333, md0), inv(2333, md1));
    for (int i = 1; i < n * 2; ++i) {
      p[i] = p[i - 1] * base;
      inv_p[i] = inv_p[i - 1] * inv_base;
    }
    vector<hashv> pref(n * 2 + 1);
    auto query = [&](int l, int r) {
      return ((pref[r] - pref[l]) * inv_p[l]).get();
    };
    vector<int> b(n * 2);
    int l0 = n, r0 = n, l1 = n, r1 = n;
    for (int i = 0; i < n; ++i) {
      b[r1] = a[i];
      pref[r1 + 1] = pref[r1] + p[r1] * a[i];
      ++r1;
      --l0;
      b[l0] = a[i];
      pref[l0] = pref[l0 + 1] - p[l0] * a[i];
      if (!ban[i]) {
        int l = 0, r = r0 - l0;
        while (l < r) {
          int mid = (l + r + 1) >> 1;
          if (query(l0, l0 + mid) == query(l1, l1 + mid)) {
            l = mid;
          } else {
            r = mid - 1;
          }
        }
        if (l == r0 - l0 || b[l0 + l] < b[l1 + l]) {
          l1 = l0;
          r1 = r0;
        } else {
          l0 = l1;
          r0 = r1;
        }
      }
    }
    int ans = 0;
    for (int i = r1 - 1; i >= l1; --i) {
      ans = (37ll * ans + b[i]) % 20181125;
    }
    cout << "Case " << qq << ": " << ans << "\n";
  }
  return 0;
}

Mr. Panda and Kakin

因为数据随机,所以可以直接在 n \sqrt n n 附近快速找出 p p p q q q 。注意到 2 30 + 3 2^{30}+3 230+3 是质数,所以快速幂是可逆的,CRT合并即可。

#include 

using namespace std;

const int e = (1 << 30) + 3;

inline int power(int x, int y, int md) {
  int res = 1;
  while (y) {
    if (y & 1) {
      res = (long long) res * x % md;
    }
    x = (long long) x * x % md;
    y >>= 1;
  }
  return res;
}

inline int inv(int a, int md) {
  int b = md, u = 0, v = 1;
  while (a) {
    int t = b / a;
    b -= t * a;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  if (u < 0) {
    u += md;
  }
  return u;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    long long n, c;
    cin >> n >> c;
    int p = sqrt(n);
    while (n % p) {
      --p;
    }
    int q = n / p;
    int u = power(c % p, inv(e % (p - 1), p - 1), p);
    int v = power(c % q, inv(e % (q - 1), q - 1), q);
    long long ans = ((long long) u * inv(q, p) % p * q + (long long) v * inv(p, q) % q * p) % n;
    cout << "Case " << qq << ": " << ans << "\n";
  }
  return 0;
}

Ultra Weak Goldbach’s Conjecture

哥德巴赫猜想,直接暴力枚举质数找解即可。

#include 

using namespace std;

bool check(long long n) {
  for (int i = 2; (long long) i * i <= n; ++i) {
    if (n % i == 0) {
      return false;
    }
  }
  return true;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int tt;
  cin >> tt;
  for (int qq = 1; qq <= tt; ++qq) {
    long long n;
    cin >> n;
    if (n >= 12) {
      if (n & 1) {
        n -= 9;
        for (int i = 2; ; ++i) {
          if (check(i) && check(n - i)) {
            cout << "Case " << qq << ": 2 2 2 3 " << i << " " << n - i << "\n";
            break;
          }
        }
      } else {
        n -= 8;
        for (int i = 2; ; ++i) {
          if (check(i) && check(n - i)) {
            cout << "Case " << qq << ": 2 2 2 2 " << i << " " << n - i << "\n";
            break;
          }
        }
      }
    } else {
      cout << "Case " << qq << ": IMPOSSIBLE" << "\n";
    }
  }
  return 0;
}

你可能感兴趣的:(CodeForces Gym 102055 简要题解)