首页 > 其他分享 >codeforces 1209E2 Rotate Columns (hard version)

codeforces 1209E2 Rotate Columns (hard version)

时间:2024-07-28 20:51:44浏览次数:16  
标签:LF 状态 Rotate int 最大值 hard codeforces __ include

codeforces 1209E2 Rotate Columns (hard version) 题解

题目传送门:codeforccesluogu

思路

状压 dp ,贪心。

贪心

对于所有列,只有列中最大值在所有列的最大值中前 \(n\) 大才可能对答案有贡献。
证明:若有非前 \(n\) 大的列对某行最大值产生了贡献,则用没有被取的前 \(n\) 大的列代替该行一定更优。所以只有列中最大值在所有列的最大值中前 \(n\) 大才可能对答案有贡献。

状压 dp

定义状态 \(S\) ,表示所有行中某些行已经确认最大值的状态,用一个二进制数 \(k\) 表示 \(S\) ,\(k\) 的第 \(i\) 位表示第 \(i\) 行是否已经确定最大值。定义 \(w_i\) ,\(i\) 为一状态,表示该状态的最大全取当前列的值。

可以假设目前那些行已经确认最大值,它们形成了状态 \(j\) 。
定义数组 \(f_{i, j}\) 表示前 \(i\) 列,状态为 \(j\) 时的最大值。
容易推出状态转移方程式:\(f_{i, j} = \max_k^{k \in j}(f_{i - 1, k} + w_{j \operatorname{xor} k})\) 。
意思为:状态 \(j\) 由状态 \(j\) 的一个子状态 \(k\) 转移而来,而 \(k\) 中没有确定的行,即为 \(k \operatorname{xor} j\) 的状态需要确认,所以加上 \(w_{k \operatorname{xor} j}\) 来补足该状态的值(因为前面是 \(k\) 状态已经固定了,所以要用当前列来补),得到 \(f_{i, j}\) 。

细节

转移时可以用到枚举子集的方法。
因为枚举子集时枚举不到空集,所以要在转移前先赋值。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
typedef long long LL;

using namespace std;

const int M = 2005, N = 15;

#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

struct node{ int a[N], mx; } a[M];
int t, n, m, w[1 << N];
LL f[N][1 << N];

bool cmp(node a, node b) { return a.mx > b.mx; }

int main() {
    scanf("%d", &t);

    while (t--) {
        memset(f, 0, sizeof(f));
        memset(a, 0, sizeof(a));
        scanf("%d%d", &n, &m);
        LF(i, 0, n - 1) LF(j, 0, m - 1) {
            scanf("%d", &a[j].a[i]);
            a[j].mx = max(a[j].mx, a[j].a[i]);
        }

        sort(a, a + m, cmp);

        LF(i, 0, min(n - 1, m - 1)) {
            LF(j, 0, (1 << n) - 1) { // 枚举状态 j ,预处理 w 数组方便后面处理
                w[j] = 0;

                LF(k, 0, n - 1) {
                    int res = 0;
                    LF(l, 0, n - 1) if ((1 << l) & j) res += a[i].a[(l + k) % n];
                    w[j] = max(w[j], res);
                }
            }

            LF(j, 0, (1 << n) - 1)
                if (i == 0) f[0][j] = w[j];
                else {
                    f[i][j] = f[i - 1][j];
                    for (int k = j; k; k = (k - 1) & j) f[i][j] = max(f[i][j], f[i - 1][k] + w[j ^ k]); // 枚举子集
                }
        }

        printf("%lld\n", f[min(n - 1, m - 1)][(1 << n) - 1]);
    }
    return 0;
}

“人生大病只是一傲字。” —— 《传习录》

标签:LF,状态,Rotate,int,最大值,hard,codeforces,__,include
From: https://www.cnblogs.com/faruzan/p/18328849

相关文章

  • Codeforces Round 961 (Div. 2)
    Preface菜的批爆,B2一直WA道心破碎了直接白兰去了,鉴定为纯纯的飞舞本来想着周末补题的然后又摆了一天,E1和E2都没时间补了,鉴定为纯纯的懒狗A.Diagonals签到,贪心枚举即可#include<cstdio>#include<iostream>#include<utility>#include<vector>#include<cstring>#in......
  • CodeForces 1883G1 Dances (Easy version)
    题目链接:CodeForces1883G1【Dances(Easyversion)】思路    为了使得数组a,b中的每个对应元素满足a[i]<b[i],所以将数组a,b按从小到大依次排列,优先删除数组a中较大的元素和数组b中较小的元素,由于删去的元素个数具有单调性,所以使用二分优化,计算最少要删去几个元素。......
  • 699. 掉落的方块 Hard
    在二维平面上的x轴上,放置着一些方块。给你一个二维整数数组 positions ,其中 positions[i]=[lefti,sideLengthi] 表示:第 i 个方块边长为 sideLengthi ,其左侧边与x轴上坐标点 lefti 对齐。每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿y......
  • CodeForces 1883F You Are So Beautiful
    题目链接:CodeForces1883F【YouAreSoBeautiful】思路    要找出一个子数组使得在数组中只能找出一个子序列和当前子数组相等,则只需要找出首元素的数字必须为当前元素值第一次出现,尾元素的数字必须为当前元素值最后一次出现,则只能找出唯一的子序列和当前子数组相等。......
  • codeforces 1209E1 Rotate Columns (easy version)
    codeforces1209E1RotateColumns(easyversion)题目传送门:codeforcces,luogu思路贪心,暴力搜索贪心对于所有列,只有列中最大值在所有列的最大值中前\(n\)大才可能对答案有贡献。证明:若有非前\(n\)大的列对某行最大值产生了贡献,则用没有被取的前\(n\)大的列代替该行......
  • Codeforces Round 962 (Div. 3) 题解 A-F
    A.LegsProblem-A-Codeforces1.1翻译农夫约翰的农场又迎来了美好的一天。农夫约翰来到农场后,数了数n条腿。众所周知,农场里只住着鸡和牛,一只鸡有2条腿,而一头牛有4条腿。假设约翰农场主数清了所有动物的腿,那么他的农场里最少有多少动物?1.2思路求最少有几只动物......
  • Codeforces Round 962 (Div. 3)
    题目链接:CodeforcesRound962(Div.3)总结:ABC秒过,D有点难评了,E优化很妙。A.Legstag:签到voidsolve(){cin>>n;inta=n/4,b=n%4;a+=b/2;cout<<a<<endl;}B.Scaletag:模拟voidsolve(){cin>>n>>k;......
  • CodeForces 1883E Look Back
    题目链接:CodeForces1883E【LookBack】思路    若直接对每个元素进行操作累乘至大于相邻的前一个元素时,可能最后会数据溢出,而且乘的2个数可能会很多,会时间超限。所以可以对每两个相邻的元素进行判断,判断他们之间差了2的多少次方。cnt记录的是当前元素和上个元素之间差......
  • CodeForces 1883D In Love
    题目链接:CodeForces1883D【InLove】思路    求能否找出两个区间不相交,所以将得到的区间先按区间左端点的大小从小到大排列,再按区间右端点的大小从小到大排列,此时取出最小的右端点和最大的左端点,若右端点在左端点左侧,则存在两个不相交的区间。由于需要动态操作增加减......
  • CodeForces 1883C Raspberries
    题目链接:CodeForces1883C【Raspberries】思路    依次枚举,特判k=4的情况,因为k=4可以由2个2拼凑起来,这2个2可以不在同一个元素上,如K=4时,数组a可以为2,3,2,5,7,9,此时数组中所有的元素乘积可以被4整除。若k=4时,此时数组中元素没有可以拆分出2的情况时,所有的......