分析
假设一个子集的总和现在是
,所有相同要求平均子集大小为
,给出一个数
必定要收回
有每个 都互不相同
我们把每个子集里的数拆成一个点,把替换变成一条边,就是有若干个环,每一个点只有一条出边。
可以预处理出所有的简单环,环的大小可知不超过15
所以预处理的时间是
每个点都跑一遍,一开始写成跑过的点不能再跑,有可能是一条链接一个环的情况
然后子集枚举合并就行了
总的时间复杂度是
代码
#include <bits/stdc++.h>
#define pb push_back
#define MP make_pair
using namespace std;
typedef long long ll;
const ll N = 5010;
const ll inf = 1e9;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
ll a[16][N]; ll b[16]; ll sum[16],s;
vector<pair<ll,ll> > dp[1<<16]; ll pre[1<<16];
ll low_bit(ll x){return x&(-x);}
map<ll,pair<ll,ll> > mp;
bool cmp(const pair<ll,ll> &x,const pair<ll,ll> &y)
{
return mp[x.first] < mp[y.first];
}
vector<pair<ll,ll> > v;
void dfs(ll x,ll fir,ll nd,ll psta)
{
// printf("%d %d %d %d\n",x,fir,nd,psta);
if(mp.find(nd) == mp.end()) return ;
pair<ll,ll> pr = mp[nd]; v.pb(MP(nd,x));
if(psta & (1<<(pr.first-1)))
{
if(nd == fir)
{
// printf(": %lld\n",psta);
// for(ll i=0;i<v.size();i++) printf("%lld %lld\n",v[i].first,v[i].second);
dp[psta] = v;
}
return ;
}
else dfs(pr.first,fir,s + nd - sum[pr.first],psta | (1<<(pr.first-1)));
}
int main()
{
// freopen("a.in","r",stdin);
ll k = read(); s = 0;
for(ll i=1;i<=k;i++)
{
b[i] = read(); s = 0;
for(ll j=1;j<=b[i];j++) a[i][j] = read(),s+=a[i][j],mp[a[i][j]] = MP(i,j);
sum[i] = s;
}s = 0; for(ll i=1;i<=k;i++) s += sum[i];
// printf("%d\n",s);
if(s%k != 0){puts("No"); return 0;}
else
{
s/=k;
for(ll i=0;i<(1<<k);i++) dp[i].clear();
for(ll i=1;i<=k;i++)
{
for(ll j=1;j<=b[i];j++){v.clear(); dfs(i,a[i][j],s + a[i][j] - sum[i],(1<<(i-1)));}
}
}
for(ll i=1;i<(1<<k);i++) if(!dp[i].size())
{
for(ll j=(i-1)&i;j;j=(j-1)&i) if(dp[j].size() && dp[i^j].size())
{
for(auto e : dp[j]) dp[i].pb(e);
for(auto e : dp[i^j]) dp[i].pb(e);
break ;
}
}
if(!dp[(1<<k)-1].size()){puts("No"); return 0;}
else
{
puts("Yes");
sort(dp[(1<<k)-1].begin(),dp[(1<<k)-1].end(),cmp);
for(auto e : dp[(1<<k)-1]) printf("%lld %lld\n",e.first,e.second);
}
return 0;
}