第6讲

推公式

125

在这里插入图片描述
在这里插入图片描述




#include <iostream>
#include <algorithm>

using namespace std;

/*
    整个题的解题思路就是 ,按照w+s排好序,然后在计算出 最大值即可
*/

typedef pair<int, int> PII;

const int N = 50010;   //1≤N≤50000,

int n;
PII cow[N];

int main()
{
    scanf("%d", &n);      //牛的个数
    for (int i = 0; i < n; i ++ )
    {
        int s, w;
        scanf("%d%d", &w, &s);
        cow[i] = {w + s, w};           //w表示 牛的 重量
    }

    sort(cow, cow + n);

    int res = -2e9, sum = 0;         //其中s的取值范围就是1≤Si≤1,000,000,000
    for (int i = 0; i < n; i ++ )              //sum表示压在该头牛上的 所有牛 的重量
    {
        int s = cow[i].first - cow[i].second, w = cow[i].second;    //s表示第i头牛的强壮度,w表示第i头牛的重量
        res = max(res, sum - s);
        sum += w;               //此时这个w表示上一头牛的重量
    }

    printf("%d\n", res);

    return 0;
}


绝对值不等式

AcWing 104. 货仓选址

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn=100100;

int n;

int a[maxn];


int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> a[i];

    sort(a,a+n);

    int res=0;

    for(int i=0; i<n; i++)
        res+=abs(a[i]-a[n/2]);

    cout << res << endl;
    return 0;

}

3167. 星星还是树(二维)


#include<iostream>
#include<cmath>
using namespace std;

const int maxn=10010;
const double eps=1e-4;  //注意1e-4用double来存储

int n;

double x[maxn],y[maxn];

double dis1(double x1, double y1)      //x1,y1就是 要选择的点
{
    double sum = 0.0;
    for(int i=0;i<n;i++)         //统计从(x1,y1)出发到所有点的距离之和
    {
        sum += sqrt((x[i] - x1)*(x[i] - x1) + (y[i] - y1) * (y[i] - y1));
    }

    return sum;
}

double dis(double x1)    //这个x就是 选择的x坐标
{
    double l = 0.0, r = 10000.0;
    while(r - l >= eps){
        double margin = (r - l)/3.0;      //这是对y轴进行3分
        double m1 = l + margin;
        double m2 = m1 + margin;
        if(dis1(x1, m1) <= dis1(x1, m2)) r = m2;
        else l = m1;
    }

    return dis1(x1, r);         //x1表示之前 选择的 横坐标,r表示 目前选择的纵坐标
}

int main()
{
    scanf("%d", &n);
    for(int i=0;i<n;i++){
        scanf("%lf%lf", &x[i], &y[i]);      //输入x,y坐标轴
    }

    double l = 0.0, r = 10000.0;            //r取10000,是因为x,y的范围 0≤xi,yi≤10000
    while(r - l >= eps){                      //eps设置为1e-4,表示l与r之间的距离无限接近
        double margin = (r - l) / 3.0;        //margin相当于 3分后 中间的 参数
        double m1 = l + margin;         //m1表示三分后的 第1段的最右边的端点
        double m2 = m1 + margin;            //m2表示三分后的 第2段的最右边的端点
        if(dis(m1) <= dis(m2)) r = m2;    //表示从m1出发,到其他点的距离更小,则让r=m2
        else l = m1;        //否则就是 l=m1
    }

    printf("%d", (int)(dis(r)+0.5));       //4舍5入 的算法就是+0.5

    return 0;
}

排序不等式

排队打水


#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=100010;

int n;

typedef long long LL;         //因为n是100000,就算是 每个人的打水时间为1s,则总时间为1+2+3+....+99999 为50亿,而int范围是20亿,所以res必须用long long类型

int a[maxn];

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> a[i];
    sort(a,a+n);

    LL res=0;

    for(int i=0; i<n; i++)
        res+=a[i]*(n-i-1);

    printf("%lld",res);

    return 0;
}

哈夫曼树

合并果子

在这里插入图片描述
在这里插入图片描述



#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

int main()
{
    int n;
    scanf("%d", &n);

    priority_queue<int, vector<int>, greater<int>> heap;           //小根堆
    
    

    // priority_queue<int, vector<int>, less<int>> heap;  大根堆

    while (n -- )
    {
        int x;
        scanf("%d", &x);
        heap.push(x);
    }


    int res = 0;
    while (heap.size() > 1)
    {
        int a = heap.top(); heap.pop();
        int b = heap.top(); heap.pop();
        res += a + b;
        heap.push(a + b);
    }

    printf("%d\n", res);
    return 0;
}

区间问题

区间覆盖

在这里插入图片描述


#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &W)const  //按照左端点的升序排列
    {
        return l < W.l;
    }
}range[N];

int main()
{
    int st, ed;
    scanf("%d%d", &st, &ed);       //输入一个起点和终点
    
    scanf("%d", &n);   //再输入n个区间
    
    for (int i = 0; i < n; i ++ )
    {
        int l, r;
        scanf("%d%d", &l, &r);     //输入区间段的左右端点
        range[i] = {l, r};              
    }

    sort(range, range + n);     //排序

    int res = 0;                //res表示的是 最后所选的区段的 个数
    bool success = false;           //success表示 是否成功,初始化为false
    
    for (int i = 0; i < n; i ++ )           //遍历n个区间段
    {
        int j = i, r = -2e9;        //注意r的值是-2e9,其中−109≤ai≤bi≤109,
        while (j < n && range[j].l <= st)     //j表示哪个区间,r表示所能覆盖左端点的 区间段的最大右区间
        {
            r = max(r, range[j].r);     
            j ++ ;
        }

        if (r < st)     //如果r直接小于st,则表示没有
        {
            res = -1;       //标记res为-1
            break;
        }

        res ++ ;        //否则就直接 标记 所选择了一个 区间段
        if (r >= ed)        //如果r大于等于终点,直接标记success为true,然后直接退出循环
        {
            success = true;
            break;
        }

        st = r;        //将start更新为右端点最大值
        i = j - 1;          //因为在上面 找到的j会向后++,但是下面i的值又会自增,所以必须将i=j-1
    }

    if (!success) res = -1;
    printf("%d\n", res);

    return 0;
}

区间分组

在这里插入图片描述
在这里插入图片描述


#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 100010;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &W)const
    {
        return l < W.l;
    }
}range[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }

    sort(range, range + n);

    priority_queue<int, vector<int>, greater<int>> heap;              //为什么要用小根堆存放?

    for (int i = 0; i < n; i ++ )
    {
        auto r = range[i];               // r表示当前所判断的区间
        if (heap.empty() || heap.top() >= r.l)            //heap.top()应该表示所有组的右端点的最小值
            heap.push(r.r);                                         //表示需要将r放到一个新的组中
        else    //将r放到原先的组中,同时也就更新了每个组的最右边的值
        {
            heap.pop();
            heap.push(r.r);
        }
    }

    printf("%d\n", heap.size());



    return 0;
}


最大不相交区间数量

在这里插入图片描述



#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=100010;

int n;

struct node
{
    int l,r;
    bool operator<(const node &t) const
    {
        return r<t.r;
    }
}Node[maxn];

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
    {
        cin >> Node[i].l >> Node[i].r;
    }
    sort(Node,Node+n);

    int res=0,ed=-1e9;
    
    for(int i=0; i<n; i++)
    {
        if(ed<Node[i].l)
        {
            ed=Node[i].r;
            res++;
        }
    }

    cout << res;
    return 0;


}

区间选点

在这里插入图片描述



#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=100010;

int n;

struct node
{
    int l,r;

    bool operator<(const node &t) const
    {
        return r<t.r;
    }
}Node[maxn];

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
        cin >> Node[i].l >> Node[i].r;
    sort(Node,Node+n);

    int res=0,ed=-1e9;

    for(int i=0; i<n; i++)
    {
        if(ed<Node[i].l)
        {
            res++;
            ed=Node[i].r;
        }
    }

    cout << res;

    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值