P3531 [POI2012]LIT-Letters(樹狀數組||逆序對)

轉換成求逆序對的問題。

如果沒有重複的字母,顯然是一一對應,用第二個串裏對應字符的下標i作爲position,然後得到一個position的序列,求這個序列的逆序對個數即爲步數。

因爲每交換一次,最多少一組逆序對。

(這個position代表一種相對前後的關係,我們只需要處理後使序列中沒有逆序對即可。)

當有重複的時候,我們發現,給它一種對應關係即可:第一個a對應第一個a....以此類推。

注意樹狀數組中不能出現0,否則lowbit會爲0,使其陷入死循環。

樹狀數組求逆序對時可以從後往前,然後add進當前值後,查詢當前樹狀數組中嚴格小於該值的數即可(sum:1~b[i]-1)。(注意下標爲數值,存的爲個數)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N=1000005;
typedef long long ll;
int n;
ll ans;
string a,b;
vector<int> v[N];
int id[N],cnt[N],t[N];
int read(){
	int num=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		num=num*10+c-'0';
		c=getchar();
	}
	return num*f;
}
int lowbit(int x){
	return x&(-x);
}
void add(int x){
	for(;x<=n;x+=lowbit(x)){
		t[x]+=1;
	}
}
int ask(int x){
	int res=0;
	for(;x;x-=lowbit(x)){
		res+=t[x];
	} 
	return res;
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read();
	cin>>a>>b;
	for(int i=0;i<n;i++){
		v[b[i]-'A'].push_back(i);
	}
	for(int i=0;i<n;i++){
		id[i+1]=v[a[i]-'A'][cnt[a[i]-'A']]+1;
		cnt[a[i]-'A']++;
	}
	for(int i=n;i>=1;i--){
		add(id[i]);
		ans+=ask(id[i]-1);
	}
	printf("%lld",ans);	
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章