tarjan缩点,枚举子集。
首先avg即平均值是可以直接求出来的,我们假设第i个盒子给出去a,那么平衡需要的是,avg-sumi+a,我们把所有数字开一个map保存下来,如果有该数字,连一条有向边,从a到avg-sumi+a。
可以看到,因为题目说了unique ,所以一个点的出度是固定的,即1。现在要求所有盒子平衡,且每个盒子必须拿出来一个值。那么我们从a连出了一条有向边,如果这是一个可行解的话,那么a会处在一个环中,即a肯定也会被需要,而且还处在当前这条链中。因出度为1,环是简单环,是一条单链。
我们就能够用tarjan缩点,把这个环求出来。
一个可行解是有多个环组成的(不可能一个环,一个环的话就是x->y->z->x,那么其实可以看到x=y=z,那么数字重复了),我们通过状压和枚举子集的方式,来看最后是否能做到。
wa点:wa了很多次,没有判断这种情况,比如一个盒子中80,1,10,平均值为100,那么1会连边10,即连接自己盒子里面的数字,这里在tarjan所点的时候需要特判。同样可能会有多个可行解,对于每一个盒子来说,我们取一个就行。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5005;
ll a[20*N];
stack<int>st;
ll k,n;
int cap[20 * N], low[20 * N], dfn[20 * N];
ll sum_bx[20];
map<ll, int>mp;
struct node {
int to, next;
}edge[40*N];
int head[40 * N];
int cnt = 0;
void addedge(int u, int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
vector<int> dp[(1 << 15)];
int tot, tar_tot;
int vis[20 * N];
struct scc_ {
vector<int>vec;
int id,sta;
}scc[20*N];
void tarjan(int u)
{
low[u] = dfn[u] = ++tot;
st.push(u);
vis[u] = 1;
for (int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u])
{
int cur = -1;
bool flag = 0;
do
{
cur = st.top(); st.pop();
scc[tar_tot].vec.push_back(cur);
if(scc[tar_tot].sta&(1 << (cap[cur] - 1)))flag=1;
scc[tar_tot].sta |= (1 << (cap[cur]-1));
vis[cur] = 0;
} while (cur != u);
if (flag||head[u] == -1 || scc[tar_tot].vec.size() == 1 && edge[head[u]].to != u) {
tar_tot++;
return;
}
if(dp[scc[tar_tot].sta].empty())dp[scc[tar_tot].sta].push_back(tar_tot);
tar_tot++;
}
}
struct ans {
int box1;
ll val;
int box2;
ans(int b1, ll v, int b2)
{
box1 = b1; val = v; box2 = b2;
}
bool operator<(const ans &b)const {
return box1 < b.box1;
}
};
vector<ans>as;
int main()
{
k = read();
int num = 0;
ll sum = 0;
memset(head, -1, sizeof(head));
upd(i, 1, k)
{
n = read();
up(j, 0, n)
{
a[++num] = read();
cap[num] = i;
mp[a[num]] = num;
sum += a[num];
sum_bx[i] += a[num];
}
}
if (sum%k) { printf("No\n"); return 0; }
ll avg = sum / k;
upd(i, 1, num)
{
ll temp = avg - sum_bx[cap[i]] + a[i];
if (mp[temp])
{
addedge(i, mp[temp]);
}
}
upd(i, 1, num)
{
if (!dfn[i])tarjan(i);
}
//cout << dp[8].size() << " " << dp[7].size();
int S = (1 << k)-1;
upd(i, 1, S)
{
for (int j = i&(i-1); j; j = (j-1)&i)
{
if (!dp[j].empty() && !dp[i^j].empty())
{
dp[i] = dp[i^j];
for (auto k : dp[j])
{
dp[i].push_back(k);
}
break;
}
}
}
if (dp[S].size() == 0) {
printf("No\n"); return 0;
}
else
{
printf("Yes\n");
for (auto k : dp[S])
{
for (int i = 0; i < scc[k].vec.size() - 1; i++)
{
ans temp(cap[scc[k].vec[i]], a[scc[k].vec[i]], cap[scc[k].vec[i + 1]]);
as.push_back(temp);
//printf("%d\n", as.back().box2);
}
as.push_back(ans( cap[scc[k].vec.back()],a[scc[k].vec.back()],cap[scc[k].vec[0]]));
// printf("%d %d %d\n", as.back().box1, as.back().val, as.back().box2);
}
sort(as.begin(), as.end());
for (auto k : as) {
printf("%lld %d\n", k.val,k.box2);
}
}
return 0;
}