Codeforces Round #599 (Div. 2) E Sum Balance(模拟+状压DP)

题目链接:https://codeforces.com/contest/1243/problem/E

题目大意:

  一共有k堆数,每堆数有 n i n_i ni个数字,每堆数字出一个数字收一个数字,要求最后每堆数的和都相同。

题目思路:

  视频推荐:传送门
  博客推荐:传送门, 这篇博客的代码非常精炼,一共也就59行,且非常优美很容易看懂,非常赞,非常推荐!
  这题每堆数字出一个收一个,出度入度都为1想到啥?肯定是环鸭,所以这题其实就是让你找到若干不相交的环,而且这些环要涉及每一个堆。由于k只有15,很容易想到可能是状压dp。
  一句话概括这道题做法:对于每个数都假设扔得是这个数,看能不能形成环,如果行的话这个环所经过的堆形成一个状态,将整个状态更新成这个环,然后通过这些环试图推出所有堆都在的情况。
  好像有点绕。。听不懂也没事,继续看!第一步,先将所有的数字加起来,看看能不能整除k,要是不行的话直接歇逼,要是行的话就能进行下一步。因为所有人都要一样嘛。而且要记录每个数字属于哪个堆,每个数字都保证不同。然后就枚举每一堆各个数字没了咋办,刚才已经知道平均数是多少,也就是最后期望需要每个堆的数字和,所以可以通过这次移除的数字,了解这个堆现在还需要的数字是多少以及需要从哪个堆里搞。然后就是模拟咯,慢慢跳,一直跳到需要的数字找不到了 or 成环了。成环也有两种情况,1-2-3-2-3-2-3,这种环算歇逼,必须要能回到起点,而且只有这么一个环。也就是这家伙跳跳跳跳到最后,如果遇到了环中的一个点,那必须是起点才行。如果他经受住了考验,那么就将他形成环的堆表示成一个状态,第一堆就是0001,第一堆和第二堆都有那就是0011大概这个意思,这里不明白就说明你可能还没学过状压dp,需要先去做做状压dp入门题。。vector里是个pair,第一维存这一行需要第几行的补给,第二维存这一行能提供什么数字,这个存放其实并不好,后期逻辑非常绕,可以参考我上面的推荐博客里的。。我当初想错了。。
  到这里预处理就结束啦!然后就是状压dp,如果对应状态的vector非空,就说明已经有结果了,那就不管他,如果没有的话,就需要尝试从已经知道的状态推出来啦!首先先用代码中这个方法遍历当前想要推出的状态的子集,然后通过这个子集异或就能得到另一边子集,观察这两个子集的解存不存在,如果存在的话就说明当前可以靠这俩子集推出来,把这俩子集搬过来就行。
  看看(1<<k)-1这个状态有没有东西,有的话就说明有解,由于刚才我的存法不好,所以这里很绕。。这里可以参考推荐博客,不用跟我学,简单介绍一下我的写法 需要先遍历一遍得到每一行提供的数字是啥,然后往ans存答案,ans的下标就是pair的第一维,对于vector来说是这个家伙需要啥,逆向思维就是被需要的这个家伙提供给的是它。而答案需要知道的是每一堆提供给了谁,所以需要逆过来。。ans的first存的是提供的是啥,刚才已经知道现在要算的是pair的第一维要提供的结果,刚才的b数组已经能够知道每一行提供的是谁,直接搬过来。second的话,根据pair的第二维,也就是这个家伙提供的是啥,我们可以通过这个家伙提供的是啥判断这个家伙是哪个堆的,因为每个数字是不同的。然后这道题就做完啦!

以下是代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define inf 0x3f3f3f3f
const ll MAXN = 1e5+5;
ll k,n[MAXN],a[20][MAXN],sum[MAXN],b[MAXN];
vector<pair<ll,ll> >v[MAXN],temp;
map<ll,ll>mp;
pair<ll,ll>ans[MAXN];
int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>k){
    
    
        ll limit=1<<k;
        rep(i,0,limit)v[i].clear();
        mp.clear();
        ll all=0;
        rep(i,1,k){
    
    
            cin>>n[i];
            sum[i]=0;
            rep(j,1,n[i]){
    
    
                cin>>a[i][j];
                mp[a[i][j]]=i;
                sum[i]+=a[i][j];
            }
            all+=sum[i];
        }
        if(all%k!=0){
    
    
            cout<<"No"<<endl;
            continue;
        }
        all/=k;
        rep(i,1,k){
    
    
            rep(j,1,n[i]){
    
    
                ll x=all-(sum[i]-a[i][j]);
                if(mp.count(x)){
    
    
                    ll sta=1<<(i-1);
                    temp.clear();
                    temp.push_back(make_pair(mp[x],a[i][j]));
                    while(x!=1e9&&x!=a[i][j]){
    
    
                        ll pos=mp[x];
                        if(((1<<(pos-1))&sta)!=0){
    
    
                            break;
                        }
                        sta|=1<<(pos-1);
                        ll p=x;
                        x=all-(sum[pos]-x);
                        if(!mp.count(x)){
    
    
                            x=1e9;
                            break;
                        }
                        else{
    
    
                            temp.push_back(make_pair(mp[x],p));
                        }
                    }
                    if(x==a[i][j]){
    
    
                        v[sta]=temp;
                    }

                }
            }
        }
        rep(i,1,limit-1){
    
    
            if(v[i].size())continue;
            for(ll j=i;j;j=(j-1)&i){
    
    
                if(v[j].size()&&v[i^j].size()){
    
    
                    ll len=v[j].size();
                    rep(k,0,len-1){
    
    
                        v[i].push_back(v[j][k]);
                    }
                    len=v[i^j].size();
                    rep(k,0,len-1){
    
    
                        v[i].push_back(v[i^j][k]);
                    }
                    break;
                }
            }
        }
        ll len=v[limit-1].size();
        if(len){
    
    
            cout<<"Yes"<<endl;
            rep(i,0,len-1){
    
    
                b[mp[v[limit-1][i].second]]=v[limit-1][i].second;
            }
            rep(i,0,len-1){
    
    
                ll p=v[limit-1][i].first;
                ans[p].second=mp[v[limit-1][i].second];
                ans[p].first=b[p];

            }
            rep(i,1,k){
    
    
                cout<<ans[i].first<<" "<<ans[i].second<<endl;
            }
        }
        else{
    
    
            cout<<"No"<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/toohandsomeIeaseId/article/details/104108428