説明
\(N \ n倍\)行列、インナーマトリックスが有する\(2N \)ボール。以下のための\(私は\ [。1、N-] \)、\ ((0、I)(I、0)\)ロボットを歩い各/アップの開始位置の後に右に行く、ロボットがボールを打つことができますそして、ボールが一緒に姿を消しました。すべてのボールが最終的に消え満たすためのソリューションのロボット開始シーケンス番号を尋ねました。
\(N \ 10 ^ {5} \)
溶液
図は、第1の平面のために、構築された\((X、Y)\ ) ボール側見たボールの位置、見ロボットの点でも\(X \)に\(N-Y + \) 、右値\(X + Yの\)側。
問題は、最終的な図のすべての側面が除去されていることをこの点に配置された操作シーケンスに変換され、エッジポイント操作が最小のものを指す側に接続され、それを削除しています。
この図は、あなたがリング上の固定点を削除したいリングの側面に各ポイントをされていないポイント、リング木の森を見つけることは困難ではない、二つのオプション、各点を時計回りと反時計回りに削除があります。
私たちは、その後、さらに構造モデル、そして今、各点がエッジを削除する必要があり、uはヴァル[U]で表さ右側を削除する各ポイントは、uはポイント右のように定義され、元のビルドに基づいて新たにすることができます図:ポイントツー各点と、彼はさえポイント値が自重未満であっても、新たなエッジの右側には、この新しい計画は今のエッジの元のセット、および森、そして質問のサブセットの外に構築されていませんでしたそれぞれが操作するよりも、父親の彼らの最初のポイントを求めているプログラムの数に変換し、これは古典的な問題であり、DFS決定されたサイズは、おそらく転送について書く、カウントすることができます。
3人の息子があると仮定し、\(V_1、V_2、V_3 \) 。
\ [[U] = {サイズ[V_1] +サイズ[V_2] \サイズを選択する[V_1]} {サイズ[V_1] +サイズ[V_2] +サイズ[v_3] \サイズ[V_1] +サイズを選択するF [V_2] } [V_2] \回[v_3] F回\ \] [v_3] F F回\
コード
#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;
}