關(guān)于二分的筆記

題目:
ZJM 有 n 個作業(yè),每個作業(yè)都有自己的 DDL,如果 ZJM 沒有在 DDL 前做完這個作業(yè),那么老師會扣掉這個作業(yè)的全部平時分。所以 ZJM 想知道如何安排做作業(yè)的順序,才能盡可能少扣一點分。請你幫幫他吧!
Input:
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4
Output:
0
3
5
標(biāo)題既然是二分,這題就應(yīng)該……好吧這題其實是上一次題目的延申。這是一道貪心題。思想也很簡單。首先根據(jù)ddl,從大到小排列,因為比如第四天,第一天ddl 的事情你根本……毫無能力做什么。
所以就倒著來,沒到一天,就把這一天ddl的所有事情扔進一個大根堆里面,每天從堆頂取一個元素就是今天要干的事情

#include<iostream>
#include<algorithm>
#include<queue> 
using namespace std;
struct ddl1
{
    int ddl;
    int score;
    bool operator<(const ddl1 a) const
    {
        return score < a.score;
    }
};
ddl1 a[2000];
bool cmp(ddl1 &x, ddl1 &y)
{
    if (x.ddl > y.ddl)
    {
        return 1;
    }
    else if (x.ddl < y.ddl)
    {
        return 0;
    }
    else
    {
        return x.score > y.score;
    }
}
int main()
{
    int m;
    cin>>m;
    int max;
    while(m)
    {
        max=0;
        int sum = 0;
        int kam = 0;
        int n;
        cin >> n;
        for (int i = 0; i < n; i++)
        {
            cin >> a[i].ddl;
            if(a[i].ddl>max)
            {
                max=a[i].ddl;
            }
        }
        for (int i = 0; i < n; i++)
        {
            cin >> a[i].score;
            sum += a[i].score;
        }
        sort(a, a + n, cmp);
        priority_queue<ddl1> pq;
        int x = 0;// 往后走的進度 
        for (int i = max; i > 0; i--)
        {
    
            for (int j = x; j < n; j++)
            {
                if (a[j].ddl == i)
                {
                //  cout << "hello" << endl;
                    pq.push(a[j]);
                    x++;
                }
                if (a[j].ddl != i)
                    break;
            }
            if (!pq.empty())
            {
                ddl1 ks = pq.top();
                kam += ks.score;
            //  cout << " " << ks.score << endl;
                pq.pop();
            }
        }
        int tmp = sum - kam;
        //cout << sum << endl;
    //  cout << kam << endl;
        cout << tmp << endl;
        m--;
    }
    return 0;
}

不太難,有了基本思路就開始碼了。
2.ZJM 有四個數(shù)列 A,B,C,D,每個數(shù)列都有 n 個數(shù)字。ZJM 從每個數(shù)列中各取出一個數(shù),他想知道有多少種方案使得 4 個數(shù)的和為 0。
當(dāng)一個數(shù)列中有多個相同的數(shù)字的時候,把它們當(dāng)做不同的數(shù)對待。請你幫幫他吧!
in
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
out
5
這題是一個典型的簡單的二分。既然是要找四個組里面的元素,首先想到的是O(n4)的遍歷,但你也看見可怕的時間復(fù)雜度,所以不妨先把兩組里面的和都給找出來,看看是不是能匹配相反數(shù)。這樣時間復(fù)雜度就暴降了,然后用個快排再用個二分查找時間復(fù)雜度就是O(n2 lognlogn)

#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(int a, int b)
{
    return a < b;
}
int tmp = 0;
void findit(int a[], int lf, int rt, int k)
{
    while (lf <= rt)
    {
        int w = (lf + rt) / 2;
        if (k == a[w])
        {
            lf = w + 1;
        }
        else if (k < a[w])
        {
            rt = w - 1;
        }
        else if (k > a[w])
        {
            lf = w + 1;
        }
    }
    for(int d=lf;d>0;d--)
    {
        if(a[d]==k)
        {
            tmp++;
        }
        else
        {
            break;
        }
    }
}
int a[4000 + 5];
int b[4000 + 5];
int a2[4000 + 5];
int b2[4000 + 5];
int c[16000000 + 5];
int main()
{
    int n;
    cin >> n;
    int tl = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i] >> b[i] >> a2[i] >> b2[i];
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            c[tl] = a[i] + b[j];
            tl++;
        }
    }
    c[tl]=1000000000;
    tl++;
    sort(c, c + tl, cmp);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            findit(c, 0, tl-1 , -(a2[i] + b2[j]));
        /*  if ()
            {
                tmp++;
            }*/
        }
    }
    findit(c, 0, tl-1 , 17);
    cout << tmp << endl;
    return 0;
}

題目:
TT 是一位重度愛貓人士,每日沉溺于 B 站上的貓咪頻道。有一天,TT 的好友 ZJM 決定交給 TT 一個難題,如果 TT 能夠解決這個難題,ZJM 就會買一只可愛貓咪送給 TT。任務(wù)內(nèi)容是:給定一個 N 個數(shù)的數(shù)組 cat[i],并用這個數(shù)組生成一個新數(shù)組 ans[i]。新數(shù)組定義為對于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。試求出這個新數(shù)組的中位數(shù),中位數(shù)即為排序之后 (len+1)/2 位置對應(yīng)的數(shù)字,’/’ 為下取整。TT 非常想得到那只可愛的貓咪,你能幫幫他嗎?

Input:
4
1 3 2 4
3
1 10 2

Output:
1
8
這幾乎是全部題目中第一個難題(很難理解)
首先二分的條件
1.有序列
2.能計算中位數(shù)是不是要找的數(shù)
3.能計算中位數(shù)是比要找的數(shù)大還是小

然后該題重點是,計算名次。
首先max=最大數(shù)減去最小數(shù)。min=0。
計算名次的方法:如果將X從小到大排列可以去絕對值。那么計算?????????≤??的二元組對數(shù)即可。移項可得????≤????+??, ??<??。
有了這個方法。我們針對最大值與最小值中間 的數(shù)就可以計算出來一個名詞。

然后條件2.3就滿足了。因為中位數(shù)的名次其實我們也是知道的((n-1)n/2+1)/2

然后一也是可以知道的,這種情況下就實現(xiàn)了二分的所有條件!

#include<iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[1000000];
/*
*/
int paiming(int x, int n)
{
    int sum = 0;
    /*for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            if (a[j] <= a[i] + x)
            {
                sum++;
            }
            else break;
        }
    }*/
    for (int i = 0; i < n; i++)
    {
        sum += n - (lower_bound(a, a + n, a[i] + x) - a);
    }
    //cout << " " << sum << endl;
    return sum;
}
int main()
{
    int n;
    while (cin >> n)
    {
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            //cin>>a[i];
        }
        sort(a, a + n);
        int rt = a[n - 1] - a[0];
        int weizhi = ((n - 1)*n / 2 + 1) / 2;
        int lf = 0;
        while (lf < rt)
        {
            int w = (lf + rt) / 2;
            int dl = paiming(w, n);
            if (dl > (n*(n - 1) / 2 - weizhi))
            {
                //cout << "1" << endl;
                //rt = w;
                lf = w + 1;
            }
            else//if (dl <= weizhi)
            {
                //cout << "2" << endl;
                //lf = w + 1;
                rt = w;
            }
        }
        cout << (lf-1) << endl;
    }
    return 0;
}

計算名次的過程我開始是直接統(tǒng)計的,可惜暴了一點錯誤(其實根本原因是遍歷的時候下標(biāo)沒控制好)。不過我沒改,直接換了C++自帶的lower_bound()返回的是數(shù)值 第一個 出現(xiàn)的位置。(其實就是偷懶了QAQ)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容