题目链接
http://codeforces.com/contest/748/problem/D
思路
只要值大于0,那么一定对我们的结果有贡献,那么尽可能的去贪心
首先,不是回文串的字符串我们必须找到它对称的字符串,一起放两边。是回文串的字符串,可能用两个放两边,也可能选出一个放中间。
我们用rem来保存放中间的那个回文串的值,oth保存放两边的回文串(如果其中有一个回文串的值小于0)的小于0的那个值
用大顶堆去维护每个字符串最大的那个值
对于每个字符串判断其是否是回文
S1:如果不是回文,它的对称字符串是否存在
S11:如果存在且它俩的和大于0,那么就把它们加入到结果中。
S12:如果不满足上述条件,终止
S2:如果是回文,统计其个数,如果为1,跳转到S21,否则到S22
S21:如果其个数为1且值大于0,那么我们可能把它加入到最中间,用rem来保存最中间的值,如果其值大于rem,更新rem。
S22:如果其个数多于1个,那么我们可能把它放到两边或者中间。
如果连续两个的和大于0,那么我们先把它俩放到两边,sum累加。如果第二个的值小于0的话,我们更新oth为min(oth, 第二个)(这代表可能将这个回文串放到最中间)。
如果连续两个的和小于0,如果第一个的和大于0,我们更新rem为max(rem, 第一个)(这代表第一个可能放中间)
最后,我们考虑把哪个回文串放中间(rem or oth)
(1)之前保存的单独的一个rem
(2)从放两边的回文串(有一个值为负)里面取负的最多的去掉,剩下的那个正值放中间。
于是,我们只需要比较rem和|oth|的值即可
代码
#include <bits/stdc++.h>
using namespace std;
inline int in() {int x; scanf("%d", &x); return x;}
#define pr(x) {cout << #x << ' ' << x << endl;}
#define LL long long
const int maxn = 100000 + 5;
int n, k;
bool is_par(string s) {
int i = 0, j = s.length() - 1;
while (1) {
if (i >= j) break;
if (s[i] != s[j]) return false;
i++; j--;
}
return true;
}
int tcnt = 0;
map<string, int> m1;
map<int, string> m2;
priority_queue<int> q[maxn];
LL sum = 0;
int main() {
k = in(); n = in();
for (int i = 0; i < k; i++) {
char s[maxn];
scanf("%s", s);
int x = in();
if (m1.find(s) == m1.end()) {
m1[s] = ++tcnt;
m2[tcnt] = s;
q[tcnt].push(x);
} else {
int ind = m1[s];
q[ind].push(x);
}
}
int rem = -INT_MAX;
int oth = 0;
for (int i = 1; i <= tcnt; i++) {
string s = m2[i];
if (is_par(s)) {
while (!q[i].empty()) {
if (q[i].size() == 1) {
if (q[i].top() > 0) {
rem = max(rem, q[i].top());
break;
} else {
break;
}
} else {
int x = q[i].top(); q[i].pop();
if (x + q[i].top() > 0) {
sum += (LL)(x + q[i].top());
if (q[i].top() < 0) oth = min(q[i].top(), oth);
q[i].pop();
} else {
if (x > 0) {
rem = max(rem, x);
break;
} else {
break;
}
}
}
}
} else {
string s2 = s;
reverse(s2.begin(), s2.end());
if (m1.find(s2) == m1.end()) continue;
int j = m1[s2];
while (!q[i].empty() && !q[j].empty() && q[i].top() + q[j].top() > 0) {
sum += (LL)(q[i].top() + q[j].top());
q[i].pop(); q[j].pop();
}
}
}
if (rem > abs(oth)) sum += (LL)rem;
else sum -= (LL)oth;
cout << sum << endl;
return 0;
}