题目链接: http://codeforces.com/problemset/problem/884/F
题目大意:定义一个字符串为反回文串, 即每一个位置与其对称的位置上的字符不相等。 给出一个长度为n的由小写字母构成的字符串s, n为偶数, 对于每一个位置i有一个价值 bi , 通过打乱原字符串的顺序, 是的该字符串成为一个反回文串, 并且对于那些与原字符串相等的位置i, ∑bi 最大。 (n≤100,bi≤100)
思路:考虑费用流建图。 用26个点表示每一个字符c, cnt[c]表示字符c出现的次数, 则源点向每一个c连一条容量为cnt[c]费用为0的边。 在用 n2 个点表示 n2 对相互对称的位置, 对于每一个字符c考虑向某一对位置(i, n - i + 1)连边, 若(i, n - i + 1)中没有c出现, 则连一条c到该点的容量为1费用为0的边; 若(i, n - i + 1)中c出现了一次, 则连一条c到该点的容量为1费用为其中出现c的位置的价值; 若(i, n - i + 1)中c出现了两次, 则连一条c到该点的容量为1费用为max(b[i], b[n - i + 1])的边。 最后对于每一对位置(i, n - i + 1)连一条指向汇点的容量为2费用为0的边。 最后跑最大费用最大流即为答案。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200;
const int M = N * N * 2;
int n; char str[N]; int ct[N], b[N];
int s, t, cnt, lst[N], nxt[M], to[M], w[M], f[M];
void add(int u, int v, int flow, int cst){
nxt[++ cnt] = lst[u]; lst[u] = cnt; to[cnt] = v; w[cnt] = cst; f[cnt] = flow;
nxt[++ cnt] = lst[v]; lst[v] = cnt; to[cnt] = u; w[cnt] = -cst; f[cnt] = 0;
}
int ans, dis[N], pre[N];
int head, tail, que[M]; bool in[N];
void spfa(){
memset(dis, -63, sizeof(dis)); dis[s] = 0;
head = 0; que[tail = 1] = s; in[s] = 1; pre[s] = 0;
while (head < tail){
int u = que[++ head]; in[u] = 0;
for (int j = lst[u]; j; j = nxt[j]){
int v = to[j];
if (!f[j]) continue;
if (dis[v] >= dis[u] + w[j]) continue;
dis[v] = dis[u] + w[j]; pre[v] = j;
if (!in[v]) in[que[++ tail] = v] = 1;
}
}
}
void update(){
ans += dis[t];
for (int k = pre[t]; k; k = pre[to[1 ^ k]]) f[k] --, f[k ^ 1] ++;
}
int main(){
scanf("%d", &n);
scanf("%s", str + 1);
for (int i = 1; i <= n; i ++) scanf("%d", b + i);
for (int i = 1; i <= n; i ++) ct[str[i] - 'a' + 1] ++;
cnt = 1;
s = n / 2 + 26 + 1, t = s + 1;
for (int i = 1; i <= 26; i ++) add(s, i, ct[i], 0);
for (int i = 1; i <= n / 2; i ++)
for (int j = 1; j <= 26; j ++){
int cc = (str[i] - 'a' + 1 == j) + (str[n - i + 1] - 'a' + 1 == j);
if (cc == 0) add(j, i + 26, 1, 0);
if (cc == 1) add(j, i + 26, 1, str[i] - 'a' + 1 == j ? b[i] : b[n - i + 1]);
if (cc == 2) add(j, i + 26, 1, max(b[i], b[n - i + 1]));
}
for (int i = 1; i <= n / 2; i ++) add(i + 26, t, 2, 0);
for (int i = 1; i <= n; i ++) spfa(), update();
printf("%d\n", ans);
return 0;
}