【離散化】離散化


百度百科

definition

對於一些數量較少但是數值較大或出現負數但難以處理的數據,如果只需要考慮他們的大小關系,可以給他們重新賦值。一般的,對於\(n\)個數據,可以將他們重新賦值為\([1,n]\)之間的數字。這種方法叫做離散化。

Solution

先介紹三個\(STL\)
\(unique\):對於一個有序數列,將之去重。一般的,若長度為\(n\)的升序序列中有\(k\)個互不相同的元素,那么經過去重的數列前\(k\)個值是這\(k\)個值按照升序排序,剩下的位置為亂序。降序排列同理。\(unique\)的調用方法是\(unique(*begin(),*end())\)其中\(begin\)\(end\)位置為序列首元素的迭代器以及序列尾元素的迭代器\(+1\).即區間左閉右開。\(unique\)函數是一個有返回值的函數,其返回值是去重后最后一個有序元素的迭代器\(+1\)。即返回一個左閉右開區間的右端點。
\(lower\)\(bound\):對於一個單調不下降數列,返回一個迭代器,迭代器的位置是第一個大於等於某個值的數。其調用方式是\(lower\)\(buond(*begin(),*end(),v)\),其中\(v\)是鍵值。迭代器的位置就是大於等於v的第一個位置。
\(upper\)__\(bound\):調用方法等同理。不同的是此函數返回的是一個嚴格大於\(v\)值的最小位置。
不要問我為什么要現學這些東西因為我以前不怎么用STL
然后,使用一個temp數組記錄原數組的值。對temp數組排序去重,那么原數組第i個位置的值就是temp去重后大於等於原數組原值的位置的值。好繞啊怎么辦,還是看代碼吧

int MU[maxn],temp[maxn];
qr(n);
for(rg int i=1;i<=n;++i) {
	qr(MU[i]);temp[i]=MU[i];
}
std::sort(temp+1,temp+1+n);
rg int cnt=std::unique(temp+1,temp+1+n)-temp-1;
for(rg int i=1;i<=n;++i) MU[i]=std::lower_bound(temp+1,temp+cnt+1,MU[i])-temp;

Example

P1774 最接近神的人

Description

小f遇到一扇門
小F發現門上有着n個數字。於是他認為打開這扇門的秘訣就是找到讓這個序列變成不下降序列所需要的最小次數。但小FF不會……只好又找到了你,並答應事成之后與你三七分……

Input

第一行為一個整數n,表示序列長度
第二行為n個整數,表示序列A中每個元素。

Output

一個整數ans,即最少操作次數。

Sample Input

4
2 8 0 3

Sample Output

3

Hint

\(1~\leq~n~\leq~5~\times~10^5\);
\(-maxlongint~\leq~A_i~\leq~maxlongint\)

Solution

根據火柴排隊那道題的經驗,我們可以得到每次交換相鄰元素將一個亂序序列變成單調不下降的步數就是序列中逆序對數。於是使用樹狀數組求逆序對。因為下標不能為負,所以考慮離散化。

Code

#include<cstdio>
#include<algorithm>
#define rg register
#define ci const int
#define cl const long long int

typedef long long int ll;

namespace IO {
	char buf[90];
}

template<typename T>
inline void qr(T &x) {
	char ch=getchar(),lst=' ';
	while(ch>'9'||ch<'0') lst=ch,ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	if(lst=='-') x=-x;
}

template<typename T>
inline void write(T x,const char aft,const bool pt) {
	if(x<0) x=-x,putchar('-');
	int top=0;
	do {
		IO::buf[++top]=x%10+'0';
		x/=10;
	} while(x);
	while(top) putchar(IO::buf[top--]);
	if(pt) putchar(aft);
}

template<typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template<typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template<typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;}

template<typename T>
inline void mswap(T &a,T &b) {
	T temp=a;a=b;b=temp;
}

const int maxn = 500010;

int n;
int MU[maxn],temp[maxn],frog[maxn];
ll ans;

inline int lowbit(ci x) {return x&((~x)+1);}

int ask(int);
void add(int);

int main() {
	qr(n);
	for(rg int i=1;i<=n;++i) {
		qr(MU[i]);temp[i]=MU[i];
	}
	std::sort(temp+1,temp+1+n);
	rg int cnt=std::unique(temp+1,temp+1+n)-temp-1;
	for(rg int i=1;i<=n;++i) MU[i]=std::lower_bound(temp+1,temp+cnt+1,MU[i])-temp;
	for(rg int i=1;i<=n;++i) {
		ans+=ask(n)-ask(MU[i]);
		add(MU[i]);
	}
	write(ans,'\n',true);
	return 0;
}

int ask(int x) {
	int _ans=0;
	while(x) {
		_ans+=frog[x];
		x-=lowbit(x);
	}
	return _ans;
}

void add(int x) {
	while(x <= n) {
		++frog[x];
		x+=lowbit(x);
	}
}

Summary

\(lower\)\(bound\):返回序列中第一個大於等於鍵值的數。
\(upper\)
\(bound\):返回序列中第一個嚴格大於鍵值的數。
區分並掌握


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM