[Codeforces 884F] Anti-Palindromize

来源:互联网 发布:蓝牙模块接线图 单片机 编辑:程序博客网 时间:2024/05/29 18:18

题目链接: http://codeforces.com/problemset/problem/884/F

题目大意:定义一个字符串为反回文串, 即每一个位置与其对称的位置上的字符不相等。 给出一个长度为n的由小写字母构成的字符串s, n为偶数, 对于每一个位置i有一个价值bi, 通过打乱原字符串的顺序, 是的该字符串成为一个反回文串, 并且对于那些与原字符串相等的位置i, bi最大。(n100,bi100)

思路:考虑费用流建图。 用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;}
原创粉丝点击