S 向每个字符连字符出现次数流量的边, 这样就保证了字符出现次数与原串相同
考虑对称位置不能相同, 我们建 n / 2 个节点, 每个字符向这 n / 2 个节点连边
如果 s[i] 和 s[n-i+1] 都是当前字符, 那么只能满足一个, 费用连 max(v[i], v[n-i+1])
如果有一个为当前字符, 那么直接连费用为它的边
如果两个都不是, 那就是去用来调节的, 连一条费用为0的边, 最后最大费用最大流就可以了
#include<bits/stdc++.h>
#define N 100050
using namespace std;
int first[N], nxt[N], to[N], w[N], c[N], tot = 1;
void add(int x, int y, int z, int v){
nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z, c[tot] = v;
nxt[++tot] = first[y], first[y] = tot, to[tot] = x, w[tot] = 0, c[tot] = -v;
}
int n, a[N], b[N]; char s[N];
int st, ed, t[N];
int dis[N], from[N], froms[N]; bool vis[N];
bool spfa(){
memset(dis, 63, sizeof(dis)); int Inf = dis[0];
memset(vis, 0, sizeof(vis));
queue<int> q; q.push(st); dis[st] = 0; vis[st] = 1;
while(!q.empty()){
int x = q.front(); q.pop(); vis[x] = 0;
for(int i=first[x];i;i=nxt[i]){
int t = to[i];
if(w[i] && dis[t] > dis[x] + c[i]){
dis[t] = dis[x] + c[i]; from[t] = x; froms[t] = i;
if(!vis[t]) vis[t] = 1, q.push(t);
}
}
} return dis[ed] != Inf;
}
int calc(){
int flow = 0x3fffffff, u = ed;
while(u){ flow = min(flow, w[froms[u]]); u = from[u];} u = ed;
while(u){ w[froms[u]] -= flow; w[froms[u] ^ 1] += flow; u = from[u];}
return flow;
}
int dinic(){ int ans = 0; while(spfa()) ans += calc() * dis[ed]; return ans;}
int main(){
scanf("%d%s", &n, s+1); st = 0; ed = 26 + n / 2 + 1;
for(int i=1; i<=n; i++) b[i] = s[i] - 'a' + 1, t[b[i]] ++;
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=26; i++){
if(!t[i]) continue;
add(st, i, t[i], 0);
for(int j=1; j<=n/2; j++){
if(b[j] == i && b[n-j+1] == i) add(i, j + 26, 1, -max(a[j], a[n-j+1]));
else if(b[j] == i) add(i, j + 26, 1, -a[j]);
else if(b[n-j+1] == i) add(i, j + 26, 1, -a[n-j+1]);
else add(i, j + 26, 1, 0);
}
}
for(int i=1; i<=n/2; i++) add(i + 26, ed, 2, 0);
printf("%d\n", -dinic()); return 0;
}