codeforces 1242C/1243 E . Sum Balance

弄了一整晚 各种bug ...最后超时,差点放弃... 然后...没指望地 随意剪了个枝.,然后......居然做出来了...

E. Sum Balance

题目大意:有k个箱子(1<=k<=15),在第i个箱子里有ni(1<=n<=5000)个整数 ( |aij|<=1e9)。所有整数都是不同的。对 每个箱子 都  进行这样的操作:从每个箱子中取出一个整数,并放入 另一个或原本的 箱子中。问能否进行这样子的操作使得 操作结束后,每个箱子的数字的和相等。

赛后补题,看了codeforces的标签:

Problem tags:bitmasks,dfs and similar,dp,graphs,implementation。

dp实在太弱,不懂该怎么做,相信dp的做法会简单很多,然而我不会。

我是从graph的思想,用dfs的方法通过bitmasks记录状态来做的....

具体:

在最开始,计算sum和aver(平均值) sum模n有余则 直接输出no

注意题目的一句话:All of the integers are distinct.

所以就是 从每个box里取一个数出来,那么重新放回去的数值aij 的 i 和j 是唯一确定的。

所以对所有box里的所有数值 它 至多有 一个相对应的数值aij , 如果假想以有向边连接这样的对应关系,那么

正解必是   从1到n   覆盖了所有的数值的  1个或多个不相交环

环里边的顶点对应的是box的标号。

所以 做法是:

对于所有box的每个点,dfs去找它所在的环,并把 环 存进 环所覆盖的box标号的 容器里。

环用二进制状压去记录。

因为每个点题目保证了只有1条出边,所以,找到环的点在之后就不用再进行判断和查找。

之后就是搜索,判断有没有1个或多个环 或起来 的值 恰好是 n个1的二进制状态。有的话就是答案,找不到就是no。

然后是,适当剪枝。

#include<bits/stdc++.h>
#define debug printf("!");
#define mp make_pair
using namespace std;
typedef long long ll;
const int maxn=5e3+50;
const int inf=0x3f3f3f3f;

int n,allstate;
ll a[16][maxn],sum,aver;
unordered_map<ll,pair<int,int>>mpp;

//tsum-tval+val=aver

struct P{
    int sta,id;
};
vector<P>vec[16];

bool vis[16][maxn];
bool dfs(int idi,int idj,int&sta,int sti,int stj)//找通过st的回路
{
    int num=a[idi][0];
    ll tsum=a[idi][num+1],val,tval=a[idi][idj];
    val=aver-tsum+tval;

    if(!mpp.count(val))return 0;

    pair<int,int>pa=mpp[val];
    if(vis[pa.first][pa.second])return 0;
    //所要访问的点有回路 这条回路不属于自己 并且 无法通过这个点找到新的回路 所以直接return false

    if(pa.first==idi&&pa.second!=idj)return 0;
    //在题意中 当前点要从box拿出去 然后将pa这个点放进来  可以是拿出去放进来同一个点 或者来自不同box的两个点 但不可能是来自同一box的不同点

    if(pa.first==sti&&pa.second==stj)
    {
        vis[idi][idj]=1;//找到回路 标记点 此后这个点不用再找回路了 因为1个点最多只有一条回路
        //因为 一个点所连的点是一个数值 题目原话:All of the integers are distinct.
        vec[idi].push_back(P{sta,idj});
        return 1;
    }
    if((1<<pa.first)&sta)return 0;
    //这个点所连的点在回路中存在  则这个sta是错的 不是单纯的回路

    sta|=(1<<pa.first);
    if(dfs(pa.first,pa.second,sta,sti,stj))
    {
        vis[idi][idj]=1;
        vec[idi].push_back(P{sta,idj});
        return 1;
    }
    return 0;
}

int ans[16];//ans[i]=j 把i集合中的j拿出去换
bool can[16][maxn];
bool cann[140000][15];
bool search(int sta)
{
    if(!sta)return 1;
    for(int i=1;i<=n;i++)
    {
        if((1<<i)&sta&&!cann[sta][i])
        {
            for(int j=0;j<vec[i].size();j++)
            {
                if(can[i][j])continue;
                if((sta&vec[i][j].sta)==vec[i][j].sta)
                {
                    if(search(sta-vec[i][j].sta))
                    {
                        ans[i]=vec[i][j].id;
                        return 1;
                    }
                }
                if(sta==allstate)can[i][j]=1;
            }
        }
        cann[sta][i]=1;
    }
    return 0;
}
int tans[16];
void last(int idi,int idj)//根据之前记录的状态记下答案
{
    int num=a[idi][0];
    ll tsum=a[idi][num+1],val,tval=a[idi][idj];
    val=aver-tsum+tval;
    pair<int,int> p=mpp[val];
    tans[p.first]=idi;
    if(ans[p.first]!=inf)return;
    ans[p.first]=p.second;
    last(p.first,p.second);
}

int main()
{
    int i,j,sta;
    ll tsum;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        allstate|=1<<i;
        scanf("%lld",&a[i][0]);
        for(j=1,tsum=0;j<=a[i][0];j++)
        {
            scanf("%lld",&a[i][j]);
            tsum+=a[i][j];
            mpp[a[i][j]]=mp(i,j);
        }
        sum+=tsum;
        a[i][j]=tsum;
    }
    if(sum%n)
    {
        puts("No");return 0;
    }
    aver=sum/n;
    for(i=1;i<=n;i++)
        for(j=1;j<=a[i][0];j++)
            if(!vis[i][j])
                dfs(i,j,sta=1<<i,i,j);
    for(i=1;i<=n;i++)
        if(!vec[i].size())
        {
            puts("No");return 0;
        }
    memset(ans,inf,sizeof(ans));
    if(search(allstate))
    {
        puts("Yes");
        for(i=1;i<=n;i++)
            if(ans[i]!=inf)last(i,ans[i]);
        for(i=1;i<=n;i++)
            printf("%lld %d\n",a[i][ans[i]],tans[i]);
    }
    else puts("No");
}

原文地址:https://www.cnblogs.com/kkkek/p/11824202.html

时间: 2024-10-04 06:35:22

codeforces 1242C/1243 E . Sum Balance的相关文章

Codeforces Round #599 E - Sum Balance

tarjan缩点,枚举子集. 首先avg即平均值是可以直接求出来的,我们假设第i个盒子给出去a,那么平衡需要的是,avg-sumi+a,我们把所有数字开一个map保存下来,如果有该数字,连一条有向边,从a到avg-sumi+a. 可以看到,因为题目说了unique ,所以一个点的出度是固定的,即1.现在要求所有盒子平衡,且每个盒子必须拿出来一个值.那么我们从a连出了一条有向边,如果这是一个可行解的话,那么a会处在一个环中,即a肯定也会被需要,而且还处在当前这条链中.因出度为1,环是简单环,是一条

Codeforces 75D Big Maximum Sum 最大子段和 dp

题目链接:点击打开链接 题意: 第一行 n m n个vector 下面n行 第一个数字u表示vector 的大小,然后后面u个数字给出这个vector 最后一行m个数字 表示把上面的vector拼接起来 得到一个大序列,求这个大序列的最大子段和 先预处理出每个vector的最大子段和,左起连续最大,右起连续最大,所有数的和 然后dp 一下.. #include <cstdio> #include <iostream> #include <algorithm> #incl

[Codeforces 1242C]Sum Balance

Description 题库链接 给你 \(k\) 个盒子,第 \(i\) 个盒子中有 \(n_i\) 个数,第 \(j\) 个数为 \(x_{i,j}\).现在让你进行 \(k\) 次操作,第 \(i\) 次操作要求从第 \(i\) 个盒子中取出一个元素(这个元素最开始就在该盒子中),放入任意一个你指定的盒子中,要求经过 \(k\) 次操作后 所有盒子元素个数和最开始相同: 所有盒子元素总和相等 询问是否存在一种操作方式使之满足,若存在,输出任意一种方案即可. \(1\leq k\leq 15

Educational Codeforces Round 5 E. Sum of Remainders (思维题)

题目链接:http://codeforces.com/problemset/problem/616/E 题意很简单就不说了. 因为n % x = n - n / x * x 所以答案就等于 n * m - (n/1*1 + n/2*2 ... n/m*m) 在根号n复杂度枚举x,注意一点当m>n时,后面一段加起来就等于0,就不用再枚举了. 中间一段x1 ~ x2 的n/x可能相等,所以相等的一段等差数列求和. 1 //#pragma comment(linker, "/STACK:1024

codeforces #319 B - Modulo Sum (抽屉原理,dp)

B - Modulo Sum Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Description You are given a sequence of numbers a1, a2, ..., an, and a number m. Check if it is possible to choose a non-empty subsequence aij 

CodeForces - 1073E :Segment Sum (数位DP)

You are given two integers l l and r r (l≤r l≤r ). Your task is to calculate the sum of numbers from l l to r r (including l l and r r ) such that each number contains at most k k different digits, and print this sum modulo 998244353 998244353 . For

【Codeforces 85 D】Sum of Medians

Codeforces 85 D 题意:维护一个有序集合,每次问编号\(mod\ 5\)余\(3\)的所有数的和. 思路:线段树维护\(mod\ 5\)余\(x\)的数的和,然后上推的时候根据左节点的值改一下就好了. Codeforces 718 A 题意:给一个小数,问最多取\(t\)次四舍五入到某一个小数点后的位后这个数最大能到多少. 思路:首先肯定贪心.(但不知道为什么tag上是\(dp\) 首先我们找到最靠左的一个大于等于5的数,把它四舍五入到上一位, 然后再不断地往前找到下一个大于等于5

cf1242C Sum Balance 【图 + 状压】

题目链接 cf1242C 题解 题意:有K个组,每组有若干个数[所有数互异],现在从每个组取出一个数,然后再将这些数分别放入一个组中,是否存在方案使得操作结束后每个组数字的和相等 最后相等的和是固定的,我们可以求出每个组距离结果的差值,对于这个组每个数,如果要将其取出,那么放入的一定就是这个数再减去这个差值的数值,而所有数互异,这样的值最多一个.这样每个数都可以找到一个这样匹配的数,向其连边,这样这张图中一个环就代表了一个轮换.如果我们能找到一组环,使得每个组都被包含一次,那么就是答案. 由于每

【CodeForces 577B】Modulo Sum

题 题意 给你n(1 ≤ n ≤ 106)个数a1..an(0 ≤ ai ≤ 109),再给你m( 2 ≤ m ≤ 103)如果n个数的子集的和可以整除m,则输出YES,否则NO. 分析 分两种情况: 当n>m时,s[i]表示前i张钱共多少钱,s[i]%m的取值为0到m-1,由抽屉原理可知,s[i]一定有重复的,假如重复的是s[l]和s[r],那么s[r]-s[l]也就是l+1到r这些钱加起来就是m 的倍数.故答案为YES. 当n≤m时,我们用dp[i][j]==1表示前i张钱可以得到对m取余为