Codeforces Round #599 E - Sum Balance

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;
}
上一篇:【洛谷 3379】最近公共祖先_Tarjan


下一篇:[USACO15DEC] 最大流Max Flow && Tarjan 线性 LCA 教学?