Codeforces Round #389 (Div. 2) D. Santa Claus and a Palindrome 回文串+贪心+数据结构、字符串

129 篇文章 0 订阅
58 篇文章 0 订阅

D. Santa Claus and a Palindrome
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Santa Claus likes palindromes very much. There was his birthday recently. k of his friends came to him to congratulate him, and each of them presented to him a string si having the same length n. We denote the beauty of the i-th string by ai. It can happen that ai is negative — that means that Santa doesn't find this string beautiful at all.

Santa Claus is crazy about palindromes. He is thinking about the following question: what is the maximum possible total beauty of a palindrome which can be obtained by concatenating some (possibly all) of the strings he has? Each present can be used at most once. Note that all strings have the same length n.

Recall that a palindrome is a string that doesn't change after one reverses it.

Since the empty string is a palindrome too, the answer can't be negative. Even if all ai's are negative, Santa can obtain the empty string.

Input

The first line contains two positive integers k and n divided by space and denoting the number of Santa friends and the length of every string they've presented, respectively (1 ≤ k, n ≤ 100 000n·k  ≤ 100 000).

k lines follow. The i-th of them contains the string si and its beauty ai ( - 10 000 ≤ ai ≤ 10 000). The string consists of n lowercase English letters, and its beauty is integer. Some of strings may coincide. Also, equal strings can have different beauties.

Output

In the only line print the required maximum possible beauty.

Examples
input
7 3
abb 2
aaa -3
bba -1
zyz -4
abb 5
aaa 7
xyx 4
output
12
input
3 1
a 1
a 2
a 3
output
6
input
2 5
abcde 10000
abcde 10000
output
0
Note

In the first example Santa can obtain abbaaaxyxaaabba by concatenating strings 5276 and 3 (in this order).




Source

 
Codeforces Round #389 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 3)


My Solution

题意:给出k个长度为n的字符串且每个字符串有一个权值,选一些字符串构成一个回文串,使这个回文串的总权值尽可能大,就权值的最大值。


 
回文串+贪心+数据结构、字符串

把字符串和权值储存在map<string,  vector<int> > mp里,用map<string, bool> flag来标记字符串是否为回文串。

选尽可能多的字符串对x + y > 0,x与y互为回文,且xy都优先选大的,其中分成本身是回文串的和不是回文串2类讨论,

如果本身是回文串,且个数大于2,而且x + y > 0,则也ans += x + y,并判断

如果 x < 0 则 minpadd = min(minpadd, x), 如果y < 0 则 minpadd = min(minpadd, y)

然后遍历flag,找出一个单独的剩余的回文串的正的最大值ansplus。

如果minpadd被维护过,即ans里存在自身为回文串的字符串对且虽然权值和为正数但其中一个权值为负数,

                    则把-minpadd 与ansplus比较,如果-minpadd 比ansplus大,则把那个回文串对的正的作为构成的大回文串的中心而负的那个去掉,

                                                                             如果 ansplus更大,值直接加到ans里就好

                     即if(minpadd != 1) ans += max(-minpadd, ansplus);

如果minpadd没有被维护过,则直接把ansplus加上去, ans += ansplus。

复杂度 O(nk*klogn)


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 8;

string s;
int v;
map<string, vector<int> > mp;
map<string, bool> flag;
int main()
{
    #ifdef LOCAL
    freopen("d.txt", "r", stdin);
    //freopen("d.out", "w", stdout);
    int T = 4;
    while(T--){
    #endif // LOCAL
    ios::sync_with_stdio(false); cin.tie(0);

    int k, n, a, b;
    cin >> k >> n;
    bool ok;
    for(int i = 0; i < k; i++){
        cin >> s >> v;
        mp[s].push_back(v);
        if(mp[s].size() == 1){
            ok = true;
            for(int j = 0; j < n / 2; j++){
                if(s[j] != s[n - 1 - j]){
                    ok = false;
                    break;
                }
            }
            if(ok) flag[s] = true;
        }

    }

    for(auto i = mp.begin(); i != mp.end(); i++){
        sort((i->second).begin(), (i->second).end());
    }


    int ans = 0, minpadd = 1, sz;
    for(auto i = mp.begin(); i != mp.end(); i++){
        s = i->first;
        reverse(s.begin(), s.end());
        if(s != (i->first)){
            while(!mp[s].empty() && !(i->second).empty()){
                a = *((i->second).rbegin());
                b = *(mp[s].rbegin());
                if(a + b > 0){
                    ans += a + b;
                    (i->second).pop_back();
                    mp[s].pop_back();
                }
                else break;

            }
        }
        else{
            sz = mp[s].size();
            while(sz >= 2){
                a = mp[s][sz-1];
                b = mp[s][sz-2];
                if(a + b > 0){
                    ans += a + b;
                    if(a < 0){
                        minpadd = min(minpadd, a);
                    }
                    else if(b < 0){
                        minpadd = min(minpadd, b);
                    }
                    mp[s].pop_back();
                    mp[s].pop_back();
                    sz -= 2;
                }
                else break;

            }
        }

    }

    int ansplus = 0;
    for(auto i = flag.begin(); i != flag.end(); i++){
        if(mp[i->first].size() > 0){
            ansplus = max(ansplus, *(mp[i->first].rbegin()));
        }
    }

    if(minpadd != 1){
        ans += max(-minpadd, ansplus);
    }
    else ans += ansplus;


    cout << ans << endl;


    #ifdef LOCAL
    mp.clear();
    flag.clear();
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}



  Thank you!

 
                                                                                                                                               ------from  ProLights
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值