1430E - String Reversal (树状数组、队列)

题目

思路:首先贪心一下,我们想要使得移动次数最小那肯定用前面离得近的元素去移动,所以我们用一个que来记录各个元素的位置,每使用完这个前面的位置的就pop掉。其次对于每一次移动我们需要知道它之前还剩多少个元素在这我们用树状数组来维护,每移去一个元素我们就让这个元素-1,初始时都为0.然后每次操作只需+que(i)-1的贡献即可。

如:3 4 5 3 7 6 3

假设我把7移到了最前面(干脆直接当作7不存在了) 3 4 5 3 (7) 6 3,那么对于原本7后面的6 3,他们下一步想要移到队首需要交换的次数比原来的次数少了一次,而对于原本7前面的数3 4 5 3它们想移动到队首所需的次数不变,而树状数组在这的运用就是改变单个点的值,直接查询区间的和(原本每个位置初始值为1表示距离,去掉之后值为0),契合树状数组。

#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int Max = 1e6 + 5;

#define lowbit(x) (x&(-x))
int c[Max], n;

void add(int x, int v){
    
    for (int i = x;i <= n;i += lowbit(i))c[i] += v;}
int que(int x)
{
    
    
    int ans = 0;
    for (int i = x;i != 0;i -= lowbit(i))ans += c[i];
    return ans;
}

queue<int> q[27];
char lst[Max];
int main()
{
    
    
    cin >> n;
    for (int i = 1;i <= n;i++)
    {
    
    
        char a;cin >> a;lst[i] = a;
        q[a - 'a'].push(i);
        add(i, 1);
    }
    ll ans = 0;
    for (int i = n;i >= 1;i--)
    {
    
    
        int pre = q[lst[i] - 'a'].front();
        q[lst[i] - 'a'].pop();
        ans+=que(pre) - 1;
        add(pre, -1);
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/asbbv/article/details/113662337