[ARC083]Collecting Balls

Description

A \ (n \ times n \) matrix, the inner matrix has \ (2N \) balls. For \ (I \ in [. 1, n-] \) , \ ((0, I) (I, 0) \) go to the right after a start position of each / up walking robot, the robot can hit the ball and the ball disappeared together. Asked the robot start sequence number of solutions to meet all the balls eventually disappear.

\ (N \ 10 ^ {5} \)

Solution

FIG first built, for a plane \ ((x, y) \ ) ball position, the point of the robot seen, seen the ball side, even an \ (X \) to the \ (n-Y + \) , the right value \ (x + y \) side.

The problem is then converted into an operation sequence arranged on this point that the final FIG all sides are removed, an edge point operation refers to the smallest one is connected to the side and remove it.

This figure is not difficult to find a ring tree forest, then point each point are not on the side of the ring you want to delete a fixed point on the ring, there are two options, each point clockwise and counterclockwise deleted.

We can further structural model, and now each point has to be deleted edge, each point u want to remove the right side denoted by val [u], u is defined as the point right, then on the basis of the original build a new Figure: each point to point and he was not even in the right side of the point value is less than its own weight even new edge, this new plan is built out of a subset of the original set of edges, and a forest, and the question now converted into a number of programs each seeking their first point of the father than to be operated, this is a classic problem, dfs determined size can count, probably write about the transfer.
Suppose there are three sons \ (v_1, v_2, V_3 \) .

\[ f[u] = {size[v_1] + size[v_2]\choose size[v_1]} {size[v_1] + size[v_2] + size[v_3]\choose size[v_1] + size[v_2]} \times f[v_2]\times f[v_3] \times f[v_3] \]

Code

#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>

typedef long long LL;
typedef unsigned long long uLL;

#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DE(x) cerr << x << endl;
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;
#define rep(i, a, b) for (register int (i) = (a); (i) <= (b); ++(i))

using namespace std;

inline void proc_status()
{
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}
inline int read() 
{
    register int x = 0; register int f = 1; register char c;
    while (!isdigit(c = getchar())) if (c == '-') f = -1;
    while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    return x * f;
}
template<class T> inline void write(T x) 
{
    static char stk[30]; static int top = 0;
    if (x < 0) { x = -x, putchar('-'); }
    while (stk[++top] = x % 10 xor 48, x /= 10, x);
    while (putchar(stk[top--]), top);
}
template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const int maxN = (int) 2e5;
const int mod = (int) 1e9 + 7;

struct Edge
{
    int v, w;
    Edge() { }
    Edge(int v, int w) : v(v), w(w) { }
} ;

int n;
bool vis[maxN + 2], instk[maxN + 2], found, in_cir[maxN + 2], choose[maxN + 2];
int top, val[maxN + 2], par[maxN + 2], size[maxN + 2];
PII stk[maxN + 2];
vector<pair<int, int> > circle;
vector<int> node;
vector<Edge> g[maxN + 2];

namespace math
{
    int fac[2 * maxN + 2], ifac[2 * maxN + 2];
    LL qpow(LL a, LL b)
    {
        LL ans = 1;
        while (b)
        {
            if (b & 1) 
                ans = ans * a % mod;
            a = a * a % mod;
            b >>= 1;
        }
        return ans;
    }
    void init()
    {
        fac[0] = 1;
        for (int i = 1; i <= 2 * n; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
        ifac[2 * n] = qpow(fac[2 * n], mod - 2);
        for (int i = 2 * n - 1; i >= 0; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    }
    int C(int n, int m) { return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod; }
    int merge(int a, int b) { return C(a + b, a); }
}
using namespace math;

void input()
{
    n = read() << 1;
    for (int i = 1; i <= n; ++i) 
    {
        int x = read(), y = read();
        g[x].emplace_back(y + n / 2, x + y);
        g[y + n / 2].emplace_back(x, x + y);
        choose[x] = choose[y + n / 2] = 1;
    }
}

void dfs_circle(int x, int fa, int edge)
{
    if (found) return;
    stk[++top] = MP(x, edge);
    instk[x] = 1;
    for (Edge E : g[x])
    {
        int v = E.v, w = E.w;
        if (v == fa) continue;
        if (!instk[v])
        {
            dfs_circle(v, x, w);
        }
        else
        {
            int To = v;
            do
            {
                v = stk[top].first;
                in_cir[v] = 1;
                circle.push_back(stk[top--]);
            } while (v != To);
            circle.back().second = w;
            found = 1;
            return;
        }
        if (found) return;
    }
    instk[x] = 0;
    top--;
}

void dfs1(int u, int fa)
{
    vis[u] = 1;
    node.push_back(u);
    for (Edge E : g[u])
    {
        int v = E.v, w = E.w;
        if (v != fa and !in_cir[v])
        {
            val[v] = w;
            dfs1(v, u);
        }
    }
}

int dfs2(int u)
{
    int ans = 1;
    size[u] = 0;
    for (Edge E : g[u])
    {
        int v = E.v;
        if (par[v] != u) continue;
        int cur = dfs2(v);
        ans = 1ll * ans * cur % mod * merge(size[u], size[v]) % mod;
        size[u] += size[v];
    }
    size[u]++;
    return ans;
}

int calc()
{
    for (int u : node)
    {
        size[u] = 0;
        par[u] = 0;
    }
    for (int u : node)
    {
        for (Edge E : g[u])
        {
            int v = E.v, w = E.w;
            if (w < val[u]) par[v] = u;
        }
    }
    int SIZE = 0, ans = 1;
    for (int u : node)
    {
        if (!par[u])
        {
            int cur = dfs2(u);
            ans = 1ll * ans * cur % mod * merge(SIZE, size[u]) % mod;
            SIZE += size[u];
        }
    }
    return ans;
}

void solve()
{
    int cnt = 0;
    for (int i = 1; i <= n; ++i)
        cnt += choose[i];
    if (cnt != n)
    {
        cout << 0 << endl;
        return;
    }
    int SIZE = 0, ans = 1;
    for (int i = 1; i <= n && ans; ++i)
    {
        if (!vis[i])
        {
            int cur = 0;
            top = 0;
            found = 0;
            circle.clear();
            dfs_circle(i, 0, 0);

            node.clear();
            for (int j = 0; j < SZ(circle); ++j) 
                dfs1(circle[j].first, 0);

            for (int j = 0; j < SZ(circle); ++j) 
                val[circle[j].first] = circle[j].second;
            (cur += calc()) %= mod;

            circle.push_back(circle[0]);
            for (int j = 1; j < SZ(circle); ++j)
                val[circle[j].first] = circle[j - 1].second;
            (cur += calc()) %= mod;

            ans = 1ll * ans * cur % mod * merge(SIZE, node.size()) % mod;
            SIZE += node.size();
        }
    }
    printf("%d\n", ans);
}

int main() 
{
#ifndef ONLINE_JUDGE
    freopen("AGC083F.in", "r", stdin);
    freopen("AGC083F.out", "w", stdout);
#endif
    input();
    math::init();
    solve();
    return 0;
}

Guess you like

Origin www.cnblogs.com/cnyali-Tea/p/11445747.html