zoukankan      html  css  js  c++  java
  • 题解 CF1430E 【String Reversal】

    题目链接

    Solution CF1430E String Reversal

    题目大意:给定一个字符串,每次操作可以交换两个相邻字符,询问最少多少次操作可以让字符串翻转

    树状数组


    分析:

    首先考虑一个 (n^2) 算法,我们找出字符串与翻转串不同的位置,往后找到第一个需要交换的位置,修改字符串并且统计答案

    rev = str;
    reverse(rev.begin(),rev.end());
    for(int i = 0;i < str.size();i++){
    	if(str[i] != rev[i]){
    		for(int j = i + 1;j < str.size();j++)
    			if(str[j] == rev[i]){
    				for(int k = j;k >= i + 1;k--)
    					str[k] = str[k - 1];
    				str[i] = rev[i];
    				ans += j - i;
    				break;
    			}
    	}
    }
    

    这样无法通过,需要优化,对于每种字符单独考虑,维护每个字符出现的位置,我们需要支持的操作:

    • 1.删除第一个数
    • 2.将小于某个阈值的所有数全部加 (1)
    • 3.询问第一个数

    可以通过差分,然后树状数组维护。位置单调,因而 (2) 操作可以二分。

    应该是(nlog^2n)带个(26)常数,跑的贼慢

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int maxn = 2e5 + 100;
    struct BIT{
    	int f[maxn];
    	inline int lowbit(int x){return x & (-x);}
    	inline void add(int pos,int x){
    		while(pos < maxn){
    			f[pos] += x;
    			pos += lowbit(pos);
    		}
    	}
    	inline int query(int pos){
    		int res = 0;
    		while(pos){
    			res += f[pos];
    			pos -= lowbit(pos);
    		}
    		return res;
    	}
    };
    struct node{
    	int val[maxn],beg = 1,end = 0;
    	BIT bit;
    	inline int top(){return val[beg] + bit.query(beg);}
    	inline int query(int pos){return val[pos] + bit.query(pos);}
    	inline void push(int x){
    		val[++end] = x;
    	}
    	inline void pop(){
    		beg++;
    	}
    	inline void modify(int limit){
    		int l = beg,r = end,ans = -1;
    		if(!end)return;
    		while(l <= r){
    			int mid = (l + r) >> 1;
    			if(bit.query(mid) + val[mid] < limit)ans = mid,l = mid + 1;
    			else r = mid - 1;
    		}
    		if(ans == -1)return;
    		bit.add(beg,1);
    		bit.add(ans + 1,-1);
    	}
    }val[26];
    inline int idx(char c){return c - 'a';}
    int n;
    long long ans;
    string str,rev;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n;
    	cin >> str;
    	rev = str;
    	reverse(rev.begin(),rev.end());
    	for(int i = 0;i < n;i++)
    		val[idx(str[i])].push(i);
    	for(int i = 0;i < n;i++){
    		int pos = val[idx(rev[i])].top();
    		ans += pos - i;
    		val[idx(rev[i])].pop();
    		for(int j = 0;j < 26;j++)
    			if(j != idx(rev[i]))val[j].modify(pos);
    	}
    	cout << ans << '
    ';
    	return 0;
    }
    

    有个更妙的做法,从逆序对的角度来考虑(可能我还是太naive了)

    假设原串每个字符的编号为 (1-n),然后我们将反串每个字符的位置按升序求出来,我们就求出了最优情况下每个字符应该变换到的位置,比如第一个样例aaaza对应的序列应该是 (1,3,4,2,5),交换相邻两数,使得数列有序,这个十分经典,答案即为这个序列的逆序对

    #include <cstdio>
    #include <string>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int maxn = 2e5 + 100;
    namespace bit{
    	int f[maxn];
    	inline int lowbit(int x){return x & (-x);}
    	inline void add(int pos,int x){
    		while(pos < maxn){
    			f[pos] += x;
    			pos += lowbit(pos);
    		}
    	}
    	inline int query(int pos){
    		int res = 0;
    		while(pos){
    			res += f[pos];
    			pos -= lowbit(pos);
    		}
    		return res;
    	}
    }
    inline int idx(char c){return c - 'a';}
    vector<int> vec[26];
    int n,val[maxn],beg[maxn];
    long long ans;
    char str[maxn],rev[maxn];
    int main(){
    	scanf("%d",&n);
    	scanf("%s",str + 1);
    	for(int i = 1;i <= n;i++)rev[i] = str[i];
    	reverse(rev + 1,rev + 1 + n);
    	for(int i = 1;i <= n;i++)
    		vec[idx(rev[i])].push_back(i);
    	for(int i = 1;i <= n;i++)
    		val[i] = vec[idx(str[i])][beg[idx(str[i])]++];
    	for(int i = n;i >= 1;i--)
    		ans += bit::query(val[i]),bit::add(val[i],1);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Opencv3 Robert算子 Sobel算子 拉普拉斯算子 自定义卷积核——实现渐进模糊
    Opencv3 形态学操作
    Opencv3 图片膨胀与腐蚀
    opencv3 图片模糊操作-均值滤波 高斯滤波 中值滤波 双边滤波
    Realsense D430 python pointclound
    opencv3读取视频并保存为图片
    Opencv3 Mat对象构造函数与常用方法
    掩膜
    Opencv图像变成灰度图像、取反图像
    ubuntu16.04 安装openpose
  • 原文地址:https://www.cnblogs.com/colazcy/p/13861692.html
Copyright © 2011-2022 走看看