2789: [Poi2012]Letters

题目链接

题目大意:给定两个字符串A和B,每次可以交换A中相邻两个字符,求最少交换多少次后A可以变成B

题解:如果串A,B中有若干个相同字母,应该把A中的1号和B中的1号配对(因为1号总是要配对,不如直接搞掉它)按照这样用B中位置对A重新编号。例如3 ABC BCA,编号为312,然后求逆序对就是答案了。

逆序对问题要求123,这显然是一个二维偏序,一维天然有序,用树状数组维护第二维。

我的收获:类似某个noip题,贪心思想Orz

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

const int M=1000005;

int n,c[M];
long long ans;
char s[M];

queue<int> q[28];

int read() {char ch=getchar();while(ch<'A'||'Z'<ch) ch=getchar();return ch-'A'+1;}

void updata(int x,int v){for(int i=x;i<=n;i+=i&(-i)) c[i]+=v;}
int query(int x){int ret=0;for(int i=x;i>0;i-=i&(-i))ret+=c[i];return ret;}

void init()
{
    cin>>n;
    scanf("%s",s+1);
    for(int i=1,t;i<=n;i++) q[t=read()].push(i);//用queue实现类似vector的功能 
    for(int i=1;i<=n;i++)
    {
        int t=s[i]-'A'+1;
        int val=q[t].front();q[t].pop();
        ans+=query(n)-query(val);//大于val的等于总数-小于等于val的
        updata(val,1);
    }
    cout<<ans<<endl;
}

int main()
{
    init();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值