CF EDU 120 E - Math Test
E - Math Test
拆绝对值
要求 \(\sum\limits_{i=1}^n|r_i-x_i|\) 的最大值,可以将绝对值拆开,对于每一个 i,若 \(r_i>=x_i\), 设 \(sgn[i] = 1\). 否则设为 \(sgn[i]=-1\), \(\sum\limits_{i=1}^n|r_i-x_i|=\sum\limits_{i=1}^nsgn[i]*r_i-sgn[i]*x_i\)
由于 n 很小,可枚举这 \(2^n\) 种符号,此时 \(\sum\limits_{i=1}^nsgn[i]*x[i]\) 已经固定,只需求 \(\sum\limits_{i=1}^nsgn[i]*r[i]\) 的最大值,\(r[i]=\sum\limits_{j=1}^m p[j]*(s[i][j] == 1)\), 因此 \(\sum\limits_{i=1}^nsgn[i]*r[i]=\sum\limits_{j=1}^mp[j]\sum\limits_{i=1}^nsgn[i]*(s[i][j]==1)\)
所以贪心的对于最小的 \(\sum\limits_{i=1}^nsgn[i]*(s[i][j]==1)\) 这道题的分值就给 1,第二小的给 2 ...
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 11, M = 1e4 + 10;
ll x[N], p[M];
int sgn[N];
int n, m;
string str[N];
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> x[i];
for (int i = 0; i < n; i++)
cin >> str[i];
for (int i = 0; i < m; i++)
p[i] = i + 1;
ll ans = 0;
for (int s = 0; s < 1 << n; s++)
{
for (int i = 0; i < n; i++)
{
if (s >> i & 1)
sgn[i] = 1;
else
sgn[i] = -1;
}
vector<PII> vt;
for (int j = 0; j < m; j++)
{
int t = 0;
for (int i = 0; i < n; i++)
t += sgn[i] * (str[i][j] == '1');
vt.push_back({t, j});
}
sort(vt.begin(), vt.end());
ll now = 0;
for (int i = 0; i < m; i++)
now += (i + 1) * vt[i].first;
for (int i = 0; i < n; i++)
now -= sgn[i] * x[i];
if (now > ans)
{
ans = now;
for (int i = 0; i < m; i++)
p[vt[i].second] = i + 1;
}
}
for (int i = 0; i < m; i++)
cout << p[i] << " ";
cout << endl;
}
return 0;
}