CSP週4問題を解決する中央の回答のC-半分

概要

すべての問題、非常に重要であるものの最初の半分を見つけるの開始前に、半分だけ、バイナリアルゴリズムに基づいて順番に基本を習得バイナリ答えアルゴリズムを理解し、対応する問題を解決します。
大きなスペースの二分法を説明する必要があるのは、ここで我々は1つの隣の公園の超詳細な説明を紹介しているので、私はあなたが固体上半期の基礎アルゴリズムを把握してからBenpianの読み取りを開始願っています:ここにポータルがあります

トピック物語

トピックの概要

TTは、B駅で毎日ふける上の深刻な猫愛好家、猫のチャネルです。
ある日、TTは、この問題を解決することができればZJMは、TT TTに問題を決めた友人、ZJMはかわいい猫がTTを与えた購入します。
概要アレイと[I] [i]を数Nアレイの猫を与えられ、新しいアレイANSが生成されます。これは、任意のI、Jのための新たな配列として定義され、iがjは=され、あるANS [] = ABS(猫[ I] -猫[J])] 1 <= I <J <= N. この新しい配列は、次いで、中央値は、位置番号に対応するソート(1 + LEN)/ 2であり、中央値を決定し、「/」丸めあります。

入力

入力の複数組、各入力1 N、Nを発現数、長さNの猫、猫のシーケンスの入力後に[I] <= 1E9、3 <= N <= 1E5

出力

出力新しい配列ANS中央値

サンプル入力

4
1 3 2 4
3
1 10 2

サンプル出力

1
8

問題の意味の修正再表示

タイトルは非常に簡単に理解することは、抽象的ではなく、より多くのように、ピットが深く掘られました
整数の配列があり、今やこれを満たす要素を満足する配列ANS []とを生成します。

ANS [] = ABS(猫[I] - 猫[J])

タスクメジアン径のこの新しい配列を解くと、データサイズは1E5です

問題解決のためのアイデア

おそらく、タイトルの最初の光景は、あなたが思うだろうねえ、これはどのようなタイトル、あまりにも多くの水です
オペレータは、次いで、複雑ではない、正常TLE始まっ直接暴力は
、対象における新アレイO ANS []複雑さ(N ^ 2)の時間を生成する際に使用される暴力的なプラクティス、プロセスn個の点を、リコール必要な時間内に1msのは不可能です。あなたはどのようにこの最適化ああ不思議に思われるかもしれませんこと?
難易度:2つのサブ機能の導入とその正当性を判断します
今回は中央値を見つけることができませんコンピューティングの完全な配列を生成するための二分法の解答方法を導入する必要があります。
以前の研究の後、あなたは理解する必要があります。限りトレンドの間隔が単調であるとして、それは二部することができます
このタイトルでは、配列の値は、直接その単調に値の配列を使用していないので、私たちはアレイと単調バイナリ解決の代わりに使用する指標を見つける必要があり、解決することはできません。
中央値が計算された配列の値が単調に増加している場合は、その要素値の前にランク付けも、バックよりも高くなければならない。この推論した後、私たちは、値の配列の半分は2のランキングとなりました変換することができます。
しかし、直接のランキングは解決できない、我々は()のソートに使用されるすべての要素が計算に関与していることを保証現在の配列保証単調、ランキングを解決するために、その後の道を、ソートする()非単調関数ABSによって制限されていた持っています一貫性のある単調な、あなたはランク付けされ、半分の使用を開始することができます。
難しII:解決ランキング
列のターゲット数が知られていないので、順位は伝統的な配列決定法では解決できません。、上記数値のそれぞれを説明し、そのランキングを得るために解くアルゴリズムのプロセスにおいて、実質的に表すことができます。

{P(i、j)を加算| I、Jを満たすはXJ-XI <= A}

この問題を解決するために、することができます列挙は、循環、私は、1つを解決する値として設定され、Aは、条件を満足するアルゴリズムを解くに変換することができる一定の値でもありJ最後に、表示されます。配列が単調に発注されているので、我々はソルバー再び進整数を使用することができます。これまでのところ、問題解決のプロセスは、すべての問題は、タイトルを排除することの難しさを解決しています。
エラーが発生しやすいポイント
対象の難しさは、我々の分析に開放されているが、実装プロセスでは、エラーが発生しやすい箇所におけるピットのいくつかのステップに簡単ですが。この質問は、コードの特定のパラメータおよび関連ノートの詳細な分析を参照してください、アシスタントは非常に痛みを伴うこともあり、最初のパスを達成することです

int search_mid(int num)//二分答案实质:对整个答案区间进行二分查找,在不知道每个具体值的情况下,利用其他的一些推导函数(例如名次)来进行查找 
{
	int left=0;
	int right=a[num-1]-a[0];
    int mid=0;
    int ans=-1;
	int mid_pos=(num*(num-1)/2+1)/2;
    while(right>=left)
    {
    	int rank=0;
        mid=(left+right)/2; 
        for(int i=0;i<num;i++)
        {
            int flag=search_j(a[i]+mid,0,num-1);
            if(flag!=-1)
            rank+=(flag-i);
        }
        if(rank>=mid_pos)
//这里用大于等于的原因是,某个数名次等于中位数,但是实际上可能并不是中位数
//因为这里的rank找的是有多少组i-j<=p,如果找的这个P在新的数列中并不存在,他等于队列中上一个比他小的数的名次
//例如新队列 4 4 4 8 8 12,找5,6,7,得到的rank都等于3,但是其实5 6 7 都不是中位数,公式:任何一个数,只要>n,<n+1,在队列中的名次都是n 
//如果在队列 4 4 4 8 8 12中找中位数,6的rank==3,但是仍然需要向前部分找---
//根本原因:rank等于中位数的这个值在生成的数列中不一定存在,且这个值一定大于要找的中位数
//所以这里规定中位数是向下取整 
        {
            right=mid-1;
            ans=mid;
        }
        else
        left=mid+1;
    }
    return ans;
}

概要

アルゴリズムの最適化は、上述した後、時間の複雑さは、対象の要件を満たすために、O(N(LOGN)^ 2)程度です。二分法の実現の前にこの質問はまだBuburは半分の答えが何であるかを知らないことがあり、どのように先の配列は、中央値を見つけることであるかを知ることができなかった疑問を呈しました。研究を繰り返し、コードを数回実施した後、二分答えの次の要約:
答えは、上位半分の整数バリアントの二分法です。
答えが半分答えが単調パラメータの一貫した変換を生成するための範囲内に存在してもよいである、連続したバイナリは、最終的に答えを見つけます
具体的な実装テンプレート:
トピック二分答えは、しばしば、標的配列は、対象範囲の整数の半分ではないこと、時間を求めてか、取得されていません。私たちは、解決しなければならないので、半分を完了し、代わりに目標範囲の制限時間の複雑さの中にリゾートの指標を見つけることです。後の指標を識別する、方法の二分法を見つけるために領域内のすべての要素の上下半分の下限及び二値化処理などの答えが、最終的に答えを見つけました。

元のタイトル

#include<iostream>
#include<cstdio>
#include <algorithm>
using namespace std;
int a[100001];
int search_j(int find_b,int left,int right)//找到j点(小于等于find_b的最后一个点)
{
    int ans=-1;
    int mid=0;
    while(left<=right)
    {
        mid=(left+right)/2;
        if(a[mid]<=find_b)
        {
            ans=mid;
            left=mid+1;
        }
        else
        right=mid-1;
    }
    return ans;
}
int search_mid(int num)
{
	int left=0;
	int right=a[num-1]-a[0];
    int mid=0;
    int ans=-1;
	int mid_pos=(num*(num-1)/2+1)/2;
    while(right>=left)
    {
    	int rank=0;
        mid=(left+right)/2; 
        for(int i=0;i<num;i++)
        {
            int flag=search_j(a[i]+mid,0,num-1);
            if(flag!=-1)
            rank+=(flag-i);
        }
        if(rank>=mid_pos)
        {
            right=mid-1;
            ans=mid;
        }
        else
        left=mid+1;
    }
    return ans;
}
int main()
{
    int number=0;
    while(scanf("%d",&number)!=EOF)
    {
    for(int i=0;i<number;i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a,a+number);
    int result=search_mid(number);
    cout<<result<<endl;
    }
    return 0;
}
公開された17元の記事 ウォンの賞賛2 ビュー1659

おすすめ

転載: blog.csdn.net/qq_43942251/article/details/104980325