zoukankan      html  css  js  c++  java
  • [HAOI2009] 求回文串

    对于任意输入的字符串,不断将第 (i) 个字符和第 (i+1) 个字符交换,使得该串最终变为回文串。求最少交换次数。(n leq 10^6)

    Solution

    直观的贪心想法:从左向右遍历每个元素,找到序列最右的与它相同的元素,将这两个元素放到目标序列最左、右端然后从原序列中删去,记录下右元素移动的距离就是答案

    然而暴力模拟的复杂度为 (O(n^2)),考虑将每种字符的所有出现位置插入一个 vector 中,同时用一个标记数组来维护每个元素是否已经被删去

    当我们从左侧找元素的时候,如果遇到了一个没有被标记的元素,就意味着我们找到了一个元素

    然后我们通过这个字符的 vector 找到最右侧的相同字符,定位到它的位置,如果这个元素在标记数组中没有被标记,则算找到,否则从 vector 中弹出这个元素并继续找

    找到以后计算贡献,并且将这个右侧元素从 vector 中抹掉,左、右两个元素同时在 vector 中标记

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    int ar[N]; // index: 1 ~ N
    int lowbit(int t) { return t & (-t); }
    void add(int i, int v) {
    	for (; i < N; ar[i] += v, i += lowbit(i));
    }
    int sum(int i) {
    	int s = 0;
    	for (; i > 0; s += ar[i], i -= lowbit(i));
    	return s;
    }
    
    char str[N];
    vector <int> v[26];
    
    int n,ans[N],u[N],tot;
    
    signed main() {
        cin>>str+1;
        n=strlen(str+1);
        for(int i=1;i<=n;i++) v[str[i]-'A'].push_back(i);
        int p1=1, p2=n;
        for(int i=1;i<=n;i++) {
            if(u[i]) continue;
            if(p1>=p2) break;
            while(v[str[i]-'A'].size() && u[v[str[i]-'A'].back()])
                v[str[i]-'A'].pop_back();
            if(v[str[i]-'A'].size()==0) {
                cout<<-1;
                return 0;
            }
            int q=v[str[i]-'A'].back();
            if(q==i) continue;
            u[q]=1;
            v[str[i]-'A'].pop_back();
            u[i]=1;
            tot+=abs(p2-q);
            ans[p1++]=i;
            ans[p2--]=q;
        }
        if(p1==p2) {
            int t=0;
            for(int i=1;i<=n;i++) if(u[i]==0) t=i;
            ans[p1]=t;
            tot+=abs(t-p1);
        }
        tot=0;
        for(int i=1;i<=n;i++) {
            tot+=i-1-sum(ans[i]);
            add(ans[i],1);
        }
        cout<<tot;
    }
    
    
  • 相关阅读:
    异常处理
    反射4中内置函数
    property装饰器与继承
    封装
    面向对象编程
    面向对象编程
    项目开发规范
    logging模块
    22. 一个题来探查对 字符串,指针,数组三方面的关联使用方面的概念是否清晰,分析下面三个printf打印什么?
    21. 让指针数组结尾带NULL,使遍历时不依靠计算整个数组大小就可以在结尾遍历结束
  • 原文地址:https://www.cnblogs.com/mollnn/p/12435061.html
Copyright © 2011-2022 走看看