Codeforces 1243E: Sum Balance 状态压缩dp

分析

假设一个子集的总和现在是 s u m [ i ] sum[i] ,所有相同要求平均子集大小为 s s ,给出一个数 a [ i ] [ j ] a[i][j]
必定要收回 s + a [ i ] [ j ] s u m [ i ] s+a[i][j] - sum[i]

有每个 a [ i ] [ j ] a[i][j] 都互不相同

我们把每个子集里的数拆成一个点,把替换变成一条边,就是有若干个环,每一个点只有一条出边。
可以预处理出所有的简单环,环的大小可知不超过15
所以预处理的时间是 O ( 5000 k 2 ) O(5000k^2) 每个点都跑一遍,一开始写成跑过的点不能再跑,有可能是一条链接一个环的情况

然后子集枚举合并就行了

总的时间复杂度是 O ( 3 k + 5000 k 2 ) O(3^k + 5000k^2)

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/102999168
今日推荐