Educational Codeforces Round 120 Editorial E【解题报告】

传送门

学会了很多骚操作

题目描述
在这里插入图片描述
在这里插入图片描述
INPUT

3
4 3
5 1 2 2
110
100
101
100
4 4
6 2 0 10
1001
0010
0110
0101
3 6
20 3 15
010110
000101
111111

OUTPUT

3 1 2
2 3 4 1
3 1 4 5 2 6

题目大意: 给你 n n n个人每个人回答 m m m个题目,随后给 n n n个字符串,代表每一门有没有回答对。对于每个学生,老师有不同的期望值 x i x_i xi,每个人实际考 ∑ i m p i ∑_i^mp_i impi记为 r i r_i ri ∣ r i − x i ∣ |r_i - x_i| rixi是惊喜值,问,当 p i p_i pi这个全排列如何取时,惊喜值之和最大。
题解
m m m的范围比较大,直接枚举全排列会死的很惨。题目其实最后求的是
∑ i n ∣ x i − r i ∣ \sum_i^n|x_i - r_i| inxiri
使其最大即可。我们可以枚举绝对值的每一个情况. Just x i − r i x_i - r_i xiri or r i − x i r_i - x_i rixi,最多有 2 n 2^n 2n种枚举方式。我们用二进制枚举。
∑ i n ∣ x i − r i ∣ = ∑ i n s i g n [ i ] r [ i ] − s i g n [ i ] x i \sum_i^n|x_i - r_i| = \sum_i^nsign[i]r[i]-sign[i]x_i inxiri=insign[i]r[i]sign[i]xi
后半部分在符号确定的时候是固定的,只需要前半部分最大即可。
∑ i n s i g n [ i ] r [ i ] = ∑ i n s i g n [ i ] ∑ j m p [ j ] ∗ a [ i ] [ j ] = ∑ j m p [ j ] ∑ i n s i g n [ i ] a [ i ] [ j ] \sum_i^nsign[i]r[i] = \sum_i^nsign[i]\sum_j^mp[j]*a[i][j] = \sum_j^mp[j]\sum_i^nsign[i]a[i][j] insign[i]r[i]=insign[i]jmp[j]a[i][j]=jmp[j]insign[i]a[i][j]
∑ i n s i g n [ i ] a [ i ] [ j ] \sum_i^nsign[i]a[i][j] insign[i]a[i][j]
记为: v a l [ j ] val[j] val[j]

答案为:
∑ j m p [ j ] ∗ v a l [ j ] \sum_j^mp[j] * val[j] jmp[j]val[j]
源代码

#include <bits/stdc++.h>

#define forn(i, n) for (int i = 0; i < int(n); ++i)

using namespace std;

int main()
{
    int T; cin >> T;
    while (T --)
    {
        int n , m;
        cin >> n >> m;
        vector<int> x(n);
        forn(i , n) cin >> x[i];
        vector<vector<int>> a(n , vector<int>(m));
        forn(i , n) forn(j , m) scanf("%1d" , &a[i][j]);
        
        int ans = -1;
        vector<int> best;
        forn(mask , 1 << n)
        {
            vector<int> val(m);
            forn(i , n) forn(j , m) if (a[i][j]) val[j] += ((mask >> i) & 1) ? +1 : -1;
            int res = 0;
            forn(i , n) res += ((mask >> i) & 1) ? -x[i] : +x[i];
            vector<int> p(m);
            iota(p.begin() , p.end() , 0);
            sort(p.begin() , p.end() , [&](int a , int b) {return val[a] < val[b];});
            forn(i , m) res += val[p[i]] * (i + 1);
            if (res > ans) ans = res , best = p;
        }
        vector<int> ansR(m);
        forn(i , m) ansR[best[i]] = i;
        forn(i , m) printf("%d " , ansR[i] + 1);
        cout << endl;
    }
    return 0;
}

参考:
https://zhuanlan.zhihu.com/p/450688661
https://codeforces.com/blog/entry/98453

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值