字符串交换相邻位置形成回文串

题意:给出一个字符串, 字符串的长度大概在10^6左右, 现在只能交换相邻两个的字符,现在要求出最少需要多少步能够形成一个回文串。

 

思路: 这道题开始的时候猜了一种做法, AC之后才想通这样的正确性。

从左向右考虑, 最左边的是u,那么找到最右边的u,然后把最右边的移动到最外边,这样子,最外边一样了,然后在考虑里边的,直至最后。最后把步数加起来就行了。 如果剩下一个单的,最后移动到中间就行了。

 

其实移动到最外边只是这个位置不再有东西了, 于是我们可以用树状数组统计步数。

下面说一下这样做的正确性。 对于最外的u的位置为i,最右边u的位置j,那么想要对应需要的最小步数是一定。如果把他们放到中间只会影响别人,放在外边也是最小的, 但是不影响别人。 这道题首先判断奇数的字母是否多余1, 如果多余1,直接输出-1,否则输出答案。

AC代码:

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 1100005, INF = 1<<25;

int in[N], n, cc[129];
bool used[N];
char str[N];
vector<int>g[129];

int lowbit(int t)
{
    return t&(t^(t-1));
}

int sum(int end)
{
    int ans=0;
    while(end>0)
    {
        ans+=in[end];
        end-=lowbit(end);
    }
    return ans;
}

void add(int pos ,int num)
{
    while(pos<=n)
    {
        in[pos]+=num;
        pos+=lowbit(pos);
    }
}

void solve()
{
    memset(in, 0, sizeof(in));
    for(int i=1; i<=n+1; i++)
    {
        add(i,1);
    }
    LL ans = 0;
    int v, u, size;
    char s;
    memset(used, 0, sizeof(used));
    for(int i=1; i<=n; i++)
    {
        if(!used[i])
        {
            s = str[i];
            size = g[s].size();
            u = g[s][size-1];
            if(i == u)
            {
                ans += (sum(n) - sum(i))/2;
            }
            else
            {
                ans += sum(n) - sum(u);
            }
            add(u, -1);
            add(i, -1);
            used[i] = used[u] = 1;
            g[s].erase(g[s].end()-1);
        }
    }
    printf("%lld", ans);
    puts("");
}

int main()
{
    while(scanf("%s", str+1) != EOF)
    {
        n = strlen(str+1);
        memset(cc, 0, sizeof(cc));

        for(int i=1; i<129; i++)
            g[i].clear();

        for(int i=1; i<=n; i++)
        {
            cc[str[i]]++;
            g[str[i]].push_back(i);
        }

        int flag = 0;
        for(int i=0; i<26; i++)
        {
            if(cc['a'+i]%2) flag++;
            if(cc['A'+i]%2) flag++;
        }
        if(flag > 1)
        {
            printf("-1");
            puts("");
            continue;
        }
        else
        {
            solve();
        }
    }
    return 0;
}
posted @ 2012-10-01 11:20  Gu Feiyang  阅读(2277)  评论(0)    收藏  举报