P1627 [CQOI2009]中位数 题解

CSDN同期

元のタイトルリンク

簡単なタイトル:

所与\(1 \) \(N- \)を見つけるために、配置された(\ B)を\の中央値である連続したサブシーケンス及び奇数の長さ数。

明らかに、このシーケンスには\(b \)が含まれています

中央値の定義:ソート後の中央の数値。

アルゴリズム1

(30 \%\)\、データ\(N- \のLeq 100 \)

このシーケンスには\(b \)が含まれている必要があるため、間隔\([i、j] \)\(b \)が含まれているダブルポインターと同様)と列挙して、\([i、j ] \)この段落は暴力的な判断で並べ替えることができます。

時間の複雑さ:\(O(n ^ 3 \ log n)\)

実際のスコア:\(30pts \)

アルゴリズム2

(60 \%\)\、データ\(N- \のLeq 1000年\)

もちろん毎回\([i、j] \)を取り出す必要はなく、何度でも展開できます。

\(i \)を列挙すると\(d \)から\(1 \)まで\(d \)\(b \)の場所です\(dから\(j \)を列挙します\) To \(n \)\(j \)ごとに、元の配列に\(a_j \)追加するだけです。\(j = n \)の場合は、配列は空です。

そして、単語の数を挿入するために、各唯一の必要性、我々は使用することができます挿入ソートを、それがソートされているように、挿入位置が半分で計算することができますので、注文しています。挿入操作に配列のメンテナンスは必要ありません。\(\ text {vector} \)を使用したメンテナンスの方がはるかに便利です。

時間の複雑さ:\(O(n ^ 2 \ log n)\)

実際のスコア:\(60pts \)

アルゴリズム3

(60 \%\)\、データ\(N- \のLeq 1000年\)

並べ替えのプロセスは別として、整理の性質上、繰り返しはありません。したがって、連続した配列の中央値\(B \)と比場合だけ\(B \)多数と数比\(B \)の値の小さい方の数が等しいです。だから、のために\(D \)線形の左側に\(\テキスト{DP} \)\(F_iと\)を表し\(I \) \(D \)より\(I \)多数の\(g_i \)の数は少なく、\(d \)の右もまた押されます。

次に、左と右のエンドポイントを列挙します\(i、j \)は、\(O(1)\)だけで判断できます。つまり、\(f_i + g_i = f_j + g_j \)です。

時間の複雑さ:\(O(n ^ 2)\)

実際のスコア:\(60pts \)

アルゴリズム4

(60 \%\)\、データ\(N- \のLeq 1000年\)

アルゴリズム3の\(\ text {dp} \)から始めて\(f_i + g_i = f_j + g_j \)は\(f_i-f_j = g_i-g_j \)同等であることがわかります。したがって、計算する必要があるのは\(B \)値の数よりも大きい\(B \)の数の数の小さい差として再利用(\ F)\状態配列の、その後のエンドポイントを挙げることができます。

時間の複雑さ:\(O(n ^ 2)\)

実際のスコア:\(60pts \)

アルゴリズム5

(100 \%\)\データ、\(N- \ 1当量5 ^ 10 \)

4番目のアルゴリズムから最適化しましょう。実際、左端が固定されている\(i \)の場合、\(j \ geq d \)\(f_i = f_j \)の数を計算するだけで済みます

言い換えれば、我々は維持する必要があるの問い合わせの数に等しい間隔を

IQだけでは不十分で、データ構造がまとまります。したがってこのクエリには\(\ text {Treap} \)または\(\ text {Splay} \)使用できます(どのバランスボードでも使用可能)

時間の複雑さ:\(O(n \ log n)\)

実際のスコア:\(100pts \)

アルゴリズム6

(100 \%\)\データ、\(N- \ 1当量5 ^ 10 \)

アルゴリズムフィフスから始めて、あなたはそれを見つけるの間隔は、お問い合わせの数と同じであることは変更せずに、静的なクエリです。次に、あなたが使用することができ重みがツリーライン(ツリーの会長を)この問題を解決します。

時間の複雑さ:\(O(n \ log n)\)

実際のスコア:\(100pts \)

アルゴリズム7

(100 \%\)\データ、\(N- \ 1当量5 ^ 10 \)

6のアルゴリズムに基づいて、あなただけではなく、静的でなく、一定の間隔を見つける\([D、N-] \) だから我々は必要ありません重みセグメントツリーを(として理解することができます\(N \)の木のツリーライン)\(1 \)の線分ツリーのみが必要です。

時間の複雑さ:\(O(n \ log n)\)

実際のスコア:\(100pts \)

アルゴリズム8

(100 \%\)\データ、\(N- \ 1当量5 ^ 10 \)

プログラムが7番目のアルゴリズムで停止した場合、それはあなたが天才であることを示すだけで、最終的な成功からほんの数歩しか離れていません。

固定間隔は、静的に等しい数を維持します。これは非常に高いようですが、実際には\(\ text {map} \)ですか?

クラスメート:まだできます%$#^%*(%&))

さて、\(\ text {map} \)に変更すると、ずっとシンプルに感じられますよね?次に、\(f \)配列を直接省略して、\ (\ text {map} \)に直接保存します

時間の複雑さ:\(O(n \ log n)\)

実際のスコア:\(100pts \)

//为了看起来清晰 , 用了嵌套三目运算符
// q[tot+=((a[i]>b)?1:(a[i]<b)?-1:0)]++; 其实相当于这几句:
// if(a[i]>b) tot++; 
// if(a[i]<b) tot--;
// q[tot]++;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+1;

inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

int n,b,wz,a[N];
int tot,sum; ll ans=0;
map<int,int> q;

int main(){
	n=read(),b=read();
	for(int i=1;i<=n;i++) a[i]=read(),wz=(a[i]==b)?i:wz;
	for(int i=wz;i<=n;i++) q[tot+=((a[i]>b)?1:(a[i]<b)?-1:0)]++;
	for(int i=wz;i>=1;i--) ans+=q[0-(sum+=(a[i]>b)?1:((a[i]<b)?-1:0))];
	printf("%lld\n",ans);
	return 0;
}

アルゴリズム9

(200 \%\)\データ、\(N- \ 1当量7〜10 ^ \)

(実は自分の援軍)

アルゴリズム8に基づいて、この\(\ log \)を削除することができます

しかし、すぐに、下付き文字は\(10 ^ 7 \)を超えないが、負の数、おそらく\(- 10 ^ 7 \)になることがわかりました

明らかに、負の添え字をハッシュすることは、この問題の最終的な正の解決策です。

添え字\(n \)を追加します。負の添え字\(O(1)\)クエリを解決した後\(\ text {map} \)削除して\(\ log \)を解決します

時間の複雑さ:\(O(n)\)

実際のスコア:\(200pts \)

おすすめ

転載: www.cnblogs.com/bifanwen/p/12678520.html