題庫連接c++
給你 \(k\) 個盒子,第 \(i\) 個盒子中有 \(n_i\) 個數,第 \(j\) 個數爲 \(x_{i,j}\)。如今讓你進行 \(k\) 次操做,第 \(i\) 次操做要求從第 \(i\) 個盒子中取出一個元素(這個元素最開始就在該盒子中),放入任意一個你指定的盒子中,要求通過 \(k\) 次操做後spa
詢問是否存在一種操做方式使之知足,若存在,輸出任意一種方案便可。code
\(1\leq k\leq 15,1\leq n_i\leq 5000,|x_{i,j}|\leq 10^9\)ip
由題,容易發現,對於任意一個盒子,會從其中拿出一個數,再從別處(或本身拿出的)添加一個數進來。get
咱們將數的拿出放入關係抽象成邊,即從第 \(i\) 個盒子中拿出的數要放入 \(j\) 中,那麼建邊 \(i\rightarrow j\)。it
由於這張圖要求每一個節點入度和出度均爲 \(1\),顯然這張圖只能是若干個無相交的環構成的。io
如今,咱們考慮全部的拿出放入關係:class
假設我要從第 \(i\) 個盒子中拿出元素 \(x\),那麼要使得這個盒子知足最終條件,應該被放入的元素爲 \(S-sum_i+x\),其中 \(S\) 爲最終每一個盒子的元素總和,\(sum_i\) 表示第 \(i\) 個盒子最初的元素總和。map
那麼咱們建邊 \(x\rightarrow S-sum_i+x\)(注意:此時圖與以前建的圖不一樣)。咱們須要在這張圖中找到全部知足下列條件的環:數據
用 \(dfs\) 找到這些環以後咱們能夠將盒子狀壓。具體地,令 \(f_i\) 表示狀態 \(i\) 中全部的盒子構成的知足條件的圖是否存在。轉移枚舉子集 \(dp\)。
若 \(f_{2^k-1}=1\) 即有解。注意另開數據記錄轉移關係,方便輸出方案。
#include <bits/stdc++.h> #define ll long long #define pb push_back using namespace std; const int N = 5000*15+5, B = (1<<15)+5; map<ll, int> mp; int k, n[20], id[N], kp[N], tot; int bin[20], x[16][5005], f[B], ok[B], p[B], vis[N], s[N], top; ll sum[20], S; vector<int> to[N], re[B]; int l[20], r[20]; void dfs(int u, int st) { if (vis[u]) { int now = 0; for (int i = top; i; i--) { now |= bin[id[s[i]]-1]; if (u == s[i]) break; } if (!ok[now]) { ok[now] = 1; for (int i = top; i; i--) { re[now].pb(s[i]); if (u == s[i]) break; } } return; } if (st&bin[id[u]-1]) return; st |= bin[id[u]-1], vis[u] = 1, s[++top] = u; for (auto v : to[u]) dfs(v, st); vis[u] = 0, --top; } int main() { bin[0] = 1; for (int i = 1; i <= 15; i++) bin[i] = bin[i-1]<<1; scanf("%d", &k); for (int i = 1; i <= k; i++) { scanf("%d", &n[i]); for (int j = 1; j <= n[i]; j++) scanf("%d", &x[i][j]), mp[x[i][j]] = ++tot, kp[tot] = x[i][j], id[tot] = i, sum[i] += x[i][j]; S += sum[i]; } if (S%k) {puts("No"); return 0; } S /= k; for (int i = 1; i <= k; i++) for (int j = 1; j <= n[i]; j++) if (mp.count(S-sum[i]+x[i][j])) to[mp[x[i][j]]].pb(mp[S-sum[i]+x[i][j]]); for (int i = 1; i <= tot; i++) dfs(i, 0); f[0] = 1; for (int i = 0; i < bin[k]; i++) if (f[i]) { int C = i^(bin[k]-1); for (int j = C; j; j = (j-1)&C) if (ok[j]) f[i|j] = 1, p[i|j] = i; } if (!f[bin[k]-1]) {puts("No"); return 0; } int x = bin[k]-1; while (x) { int U = x-p[x]; for (auto i : re[U]) { l[id[mp[S-sum[id[i]]+kp[i]]]] = S-sum[id[i]]+kp[i], r[id[mp[S-sum[id[i]]+kp[i]]]] = id[i]; } x = p[x]; } puts("Yes"); for (int i = 1; i <= k; i++) printf("%d %d\n", l[i], r[i]); return 0; }