[Codeforces 884F] Anti-Palindromize

题目链接: 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;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值