链接
题解
首先这是一个基环内向树森林
让你找出若干个环,这些环中恰好包含了每种颜色的节点各一个
先把所有环找出来并抛弃不合法的,然后记录每个环包含了哪几种颜色
最后状压 d p dp dp
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
ll a[17][5010], n[17], k, s[17], vis[17][5010];
pll to[17][5010];
vector<pll> f[(1<<15)+10];
unordered_map<ll,pll> tab;
int main()
{
ll i, j, ave;
k=read();
rep(i,k)
{
n[i]=read();
rep(j,n[i])a[i][j]=read(), s[i]+=a[i][j], s[0]+=a[i][j], tab[a[i][j]]=pll(i,j);
}
if(s[0]%k!=0)
{
printf("No");
return 0;
}
ave=s[0]/k;
rep(i,k)
{
rep(j,n[i])
{
ll want=ave-s[i]+a[i][j];
if(tab.find(want)!=tab.end())to[i][j]=tab[want];
else to[i][j]=pll(-1,-1);
}
}
unordered_map< ll, vector<pll> > table;
rep(i,k)
{
rep(j,n[i])
{
pll now=pll(i,j);
stack<pll> stk;
ll c=0;
while(1)
{
if(now.first==-1)break;
if(vis[now.first][now.second])break;
vis[now.first][now.second]=1;
stk.em(now);
now=to[now.first][now.second];
c++;
if(c>k){now=pll(-1,-1);break;}
}
if(now.first==-1)
{
while(!stk.empty())vis[stk.top().first][stk.top().second]=0, stk.pop();
continue;
}
vector<pll> v;
while(stk.top()!=now)v.emb(stk.top()), vis[stk.top().first][stk.top().second]=0, stk.pop();
while(!stk.empty())vis[stk.top().first][stk.top().second]=0, stk.pop();
v.emb(now);
ll cnt[17]={0};
for(auto x:v)cnt[x.first]++;
ll ii;
for(ii=1;ii<=15;ii++)if(cnt[ii]>1)break;
if(ii>15)
{
ll s=0;
for(auto x:v)s |= 1<<x.first-1;
table[s]=v;
}
}
}
for(i=0;i<(1<<k);i++)
for(j=i;j;j=(j-1)&i)
{
ll t = __builtin_popcount(i);
if( table.find(j)!=table.end() and f[i^j].size()+table[j].size()==t )
{
f[i]=f[i^j];
for(auto x:table[j])f[i].emb(x);
break;
}
}
pll ans[17];
if(f[(1<<k)-1].size()==k)
{
printf("Yes\n");
for(auto x:f[(1<<k)-1])
{
ans[to[x.first][x.second].first] = pll( to[x.first][x.second].second , x.first ) ;
}
for(ll i=1;i<=k;i++)printf("%lld %lld\n",a[i][ans[i].first],ans[i].second);
}
else
{
printf("No");
}
return 0;
}