天天看點

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

時間不夠代碼沒寫注釋,抱歉!!!

題目(1)

時間限制: 400 ms 記憶體限制: 64 MB 代碼長度限制: 16 KB

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

簡單分析

簡單來說就是求 N的k次方mod素數10007 這裡用到兩個公式。

費馬小定理:

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

和 基本定律 (a + b * n) mod n ≡ a mod n

詳細可以看:https://www.zybuluo.com/Lin--/note/1373807 上面有簡單描述。

代碼

int Power(int a, int b)
{
    if(a > 10007 || b > 10006)
        return Power(a%10007, b%10006);
    if(a == 0)
        return 0;
    int answer = 1, tmp = 0;
    while(tmp < b)
    {
        answer *= a;
        if(answer >= 10007)
            answer = answer % 10007;
        tmp++;
    }
    return answer;
}
           

題目(2)

時間限制: 1200 ms 記憶體限制: 24 MB 代碼長度限制: 16 KB

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數
分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

簡單分析

與兩個等長有序序列的中位數類似(折半查找和merge算法)

merge算法(僞代碼):

輸入:數組A[1...m]和它的三個索引去p,q,r,1 <= p <= q < r <= m,兩個子數組A[p...q]和A[q+1...r]各自按升序排列
輸出:合并兩個子數組A[p...q]和A[q+1...r]

comment: B[p...r]是個輔助數組
s <- p; t <- q + 1; k <- p
while s <= q and t <= r
	if A[s] <= A[t] then
		B[k] <- A[s]
		s <- s + 1
	else
		B[k] <- A[t]
		t <- t + 1
	end if
		k <- k + 1
end while
if s = q + 1 then B[k...r] <- A[t...r]
else B[k...r] <- A[s...q]
end if
A[p...r] <- B[p...r]
           

merge算法因為是得到一個新的排序是以複雜度為Θ(n),但是我們不用那麼多資訊,是以我們不需要一個個的往後比較,使用二分的方法可以将時間複雜度降為Θ(log2n)。

find_midian 的算法

輸入:數組A[1...n]和B[1...n]
輸出:兩個子數組的合并數組的中位數p
s <- 1; q <- 1; k <- m - 1
while m > 1
	if A[s + (k + 1)/2] > B[q + (k + 1)/2]) then
		s <- s + (k + 1)/2
	else
		q <- q + (k + 1)/2
	end if
	k <- k/2
end while
if A[s] < B[s](這裡輸出低位中位數) then
	p <- A[s]
else
	p <- B[s]
           

上面是等長數組的,而非等長數組我們則需要将其删減為等長數組。A[1…n]和B[1…m]兩個數組,假設n > m + 1,則數組A中存在不可能是中位數的位置。

如:若n > m + 1的情況下,即使在最極端的A[n] > B[1]的情況下,A[(m+n)/2…n]是無法被選取為中位數的,即使同理,A[1] < B[m]的情況下,A[1…(m - n)/2]也是無法被取為中位數的。

Array (A[1], A[2], ... , A[m], B[1], ... , B[n])的中位數為 A[(m+n)/2]
Array ( B[1], ... , B[n] , A[1], A[2], ... , A[m])的中位數為 A[(m-n)/2]
           

但是這裡我們把數組A删除至長度為 M + 1 ,A數組可以被選為中位數的長度段為 A [ (m - n - 1) / 2 … (m + n) / 2 ],我們仍然需要讨論特例A[(m + n) / 2],若A[(m + n) / 2] < B[0] 時,中位數就是A[(m + n) / 2]啦,如果還沒找到剩下的兩個數組丢到上面的find_midian裡面運算完就是中位數啦

代碼

int median(int *a,int *b, int n1,int n2,int lowa,int lowb)
{
    if(n1 > n2)
    {
        lowa = (n1 - n2 - 1)/2;
        if(a[lowa + n2] < b[0])
            return a[lowa + n2];
        if(a[lowa] > b[n2 - 1])
            return a[lowa];
    }
    if(n1 < n2)
    {
        lowb  = (n2 - n1 - 1)/2;
        if(b[lowb + n1] < a[0])
            return b[lowb + n1];
        if(b[lowb] > a[n1 - 1])
            return b[lowb];
    }
    int shanchu;
    if(n2 > n1)
        shanchu = n1;
    else
        shanchu = n2;
    int tmp_shan = 0;
    while(shanchu != 0)
    {
        tmp_shan = (shanchu + 1)/2;
        if(a[lowa + tmp_shan - 1] > b[lowb + tmp_shan - 1])
            lowb += tmp_shan;
        else
            lowa += tmp_shan;
        shanchu -= tmp_shan;
    }
    if(a[lowa] < b[lowb])
        return a[lowa];
    else
        return b[lowb];
}
           
備注

如果這裡沒有懂,請麻煩私聊我,之後我盡量改進自己的描述

題目(3)

時間限制: 10000 ms 記憶體限制: 64 MB 代碼長度限制: 16 KB

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

分析

簡單的排序,10000的随機正整數,用Θ(nlog2n)的任意算法都行吧。

這裡用的是快排,寫的不是很好。

代碼

#include <iostream>
using namespace std;
void quick_sort(int a[], int length)
{
    if(length < 2)
        return;
    int side = 0, tmp;
    for(int num = 1; num < length; num++)
    {
        if(a[num] > a[0])
        {
            side++;
            tmp = a[side];
            a[side] = a[num];
            a[num] = tmp;
        }
    }
    tmp = a[side];
    a[side] = a[0];
    a[0] = tmp;
    quick_sort(a,side);
    quick_sort(a+side+1,length-side-1);
}
int arr[1000000];
int main()
{
    std::ios::sync_with_stdio(false);
    int length;
    cin >> length;
    for(int num = 0; num < length; num++)
        cin >> arr[num];
    quick_sort(arr,length);
    for(int num = length - 1; num > 0; num--)
        cout << arr[num] << " ";
    cout << arr[0];
}
           

題目(4)

時間限制: 400 ms 記憶體限制: 64 MB 代碼長度限制: 16 KB

分治法 Quick Power 非等長有序序列的中位數 排序 找第k小的數

提示把算法描述的很好了,我就瞎叨叨了。

代碼

#include <iostream>
using namespace std;
int arr[1000];
int quick_sort(int arr[], int length, int k)
{
    if(length == 1)
        return arr[0];
    int side = 0, side2 = 0, tmp;
    for(int num = 1; num < length; num++)
    {
        if(arr[num] == arr[0])
            side2++;
        if(arr[num] < arr[0])
        {
            side++;
            tmp = arr[num];
            arr[num] = arr[side];
            arr[side] = tmp;
        }
    }
    if(side > k - 1 && side > 0)
        return quick_sort(arr + 1, side, k);
    else if(side + side2 < k - 1 && side + side2 > 0)
        return quick_sort(arr + side + 1, length - side - 1, k - side - 1);
    else
        return arr[0];
}
int main()
{
    std::ios::sync_with_stdio(false);
    int length, k;
    cin >> length;
    cin >> k;
    for(int tmp = 0; tmp < length; tmp++)
        cin >> arr[tmp];
    cout << quick_sort(arr,length,k);
}
           

繼續閱讀