牛牛与比赛颁奖 差分

主要通过《牛牛与颁奖比赛》来阐述差分思想,并实现。然后引入《二分 》,《Soda Machine》来巩固这个知识点。

牛牛与比赛颁奖 √

牛牛与颁奖比赛

题目描述

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

解题思路

  • 暴力解法:
    即定义数组arr[n]表示每个队伍过题的人数,然后遍历m个整数区间[l,r],对区间arr[l…r]中所有数都进行+1操作,最后对这n个队伍进行排序找出金银铜队伍的数目即可。
  • 改进:
    最耗时的就是对区间arr[l…r]所有数进行+1操作。可以看到在[l…r]这个区间里面,相邻两只队伍的过题数目并没有变化,其中l-1队伍比l队伍多一道题目, r队伍比r+1队伍多一道题目,所以可以利用差分的思想,只保留关键队伍变化的节点,即变化量,diff[i]表示第i支队伍比第i-1支队伍过题数目多多少。那么每次读取一个区间[l,r],就可以diff[l] = diff[l]+1; diff[r+1]=diff[r+1]-1;。diff定义为 map<int, int> diff; // 表示第i支队伍比第i-1支队伍过题数目差多少

在这里插入图片描述
主要思想如图所示,x轴代表所有队伍,过第一题队伍区间[0,3],过第二题的队伍[1,3], 过第三题的队伍[3,8]可以看到,0,1,3,8是变化的关键节点,关键节点表示在该节点左右两边过题数目发生变化,增加或者减少。
其中可以看到
过题目数1个的有 0 4 5 6 7 8
过题目数2个的有1 2
过题目数3个的有3
可以看到 区间变化时,整个区间的差值没有发生变化,只有区间两端端点与前一个队伍的差值发生了变化比如[0,1), [1,3), (3,8)
那么就可以利用端点差值的变化来表示整个区间的变化

map<int, int> diff; // map默认按key值升序排序
// [0,3] 0-3队伍答对一题
diff[0] = diff[0]+1; // 从0开始,[0,3]区间增加了1题
diff[4] = diff[4]-1; // [0,3]区间+1题,第4队伍比第3队伍少1题 
// [1,3]
diff[1] = diff[1]+1; // 从1开始,[1,3]区间增加了1题
diff[4] = diff[4]-1; // [1,3]区间+1题,第4队伍比第3队伍少1题 
// [3,8]
diff[3] = diff[3]+1; // 从3开始,[3,8]区间增加了1题
diff[8+1] = diff[8+1]-1; // 直到8,到第9队伍,第9队伍比第8队伍少1题

如何看出每个队伍答对多少题呢?

在这里插入图片描述
由上图可知,变化的前缀和 last ,即为当前队伍的答对题目的个数,且在变化量之间区间[l,r]中的队伍个数,即为 答对last个题的队伍个数。

    for (auto &p: diff) // 按照升序遍历发生变化的节点,前缀和【前面所有变化的和】就是当前区间答对题目的个数
    {
        cnt[last] += p.first - lastid;  // [lastid,p.first] 这个区间队伍答对题目的个数是一样的都是last, 统计 答对last题目个数的队伍有多少个
        lastid = p.first; // lastid保存上一个变化的节点
        last = p.second+last; // last 保存前缀和, 即前面所有变化的值,即diff[i]累加
    }

取排名为 [n/10] [n/4] [n/2]的队伍通过题目总数为金银铜牌线
利用cnt[i]代表答对题目数量为 i 个的队伍有多少只,然后倒序遍历 cnt 。

    for (int i= SIZE-2; i >= 0; i--) {
        cnt[i] += cnt[i+1]; // cnt[i] 保存答对数目 >= i 的队伍个数
        if (j == -1 && cnt[i] >= (n+9)/10) j=i; // 一旦队伍个数 大于等于 (n+9)/10 为金牌线
        if (y == -1 && cnt[i] >= (n+3)/4) y=i; // 一旦队伍个数 大于等于 (n+3)/4 为银牌线
        if (t == -1 && cnt[i] >= (n+1)/2) t=i;// 一旦队伍个数 大于等于 (n+1)/2 为铜牌线
    }
    

实现代码

#include <bits/stdc++.h>
using namespace std;
const int SIZE = 1e5+10;
int cnt[SIZE]; // 过题数量有多少只队伍
int main()
{
    memset(cnt, 0, sizeof(cnt));
    map<int, int> diff;
    //map<int, int> cnt;
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        diff[l] = diff[l] + 1;
        diff[r+1] = diff[r+1] - 1;
    }
    int lastid = 0, last = 0;
    //lastid记录上一个 关键队伍的编号, last记录上一个关键队伍的过题数量
    // 从左到右依次遍历
    for (auto &p: diff)
    {
        cnt[last] += p.first - lastid;
        lastid = p.first;
        last = p.second+last;
        //printf(" %d \n", last);
    }
    
  
    int j=-1, y=-1, t=-1;
    for (int i= SIZE-2; i >= 0; i--) {
        cnt[i] += cnt[i+1];
        if (j == -1 && cnt[i] >= (n+9)/10) j=i;
        if (y == -1 && cnt[i] >= (n+3)/4) y=i;
        if (t == -1 && cnt[i] >= (n+1)/2) t=i;
    }
    
    // 奖牌线不得少于1题
    j = max(j, 1);
    y = max(y, 1);
    t = max(t, 1);
    printf("%d %d %d\n", cnt[j], cnt[y]-cnt[j], cnt[t]-cnt[y]);
    
    return 0;
}

裁判最多多少次记得目标分数 √

牛客 二分

题目表述

在这里插入图片描述

解题思路
判断裁判最多有多少个回答是正确的,即在某个正整数为答案时,裁判回答正确的个数最多。
暴力解法:
遍历所有可能的正整数[1…100000],然后判断裁判的回答是否正确并统计回答正确的个数保留最大值。

5 . 在5位置 该回答正确
8 + 小于8的位置 该回答正确
5 . 在5位置 该回答正确
8 - 在大于8的位置 该回答正确
可以将上述转换为区间操作 [5,5], [1,8], [5,5] , [8, inf], 这样就可以转换为上面的差分来做。
diff[5] = diff[5]+1
diff[6]=diff[6]-1

diff[1]=diff[1]+1
diff[9]=diff[9]-1

diff[5] = diff[5]+1
diff[6]=diff[6]-1

diff[8] = diff[8]+1
diff[100100]=diff[100100]-1

代码实现

#include<bits/stdc++.h>
using namespace std;
const int SIZE = 1e5+100;
map<int, int> diff;
int n;
int cnt[SIZE+1]; // 在i处时猜对的有多少个数
int main() {
    scanf("%d", &n);
    for (int i = 1; i<= n; i++) {
        int a;
        char b;
        scanf(" %d", &a);
        scanf(" %c", &b);
        //printf("%d %c ", a, b);
        if (b == '.') {
            diff[a] = diff[a] + 1;
            diff[a+1] = diff[a+1] - 1;
        } else if (b == '+') {
            // < a 
            diff[1]= diff[1] + 1;
            diff[a] = diff[a] - 1;
            
        } else if (b == '-') {
            // > a 都加1
            diff[a+1] = diff[a+1] + 1;
            diff[INT_MAX] = diff[INT_MAX] - 1;
        }
    }
    int sum = 0, lastid = 0, maxn = 0;
    for (auto & p: diff) 
    {
        //cnt[sum] = p.first-lastid;
        sum += p.second;
        //lastid = p.first;
        maxn = max(maxn, sum);
        
    }
    // 最多有多少个回答是回答正确的。
    printf("%d\n", maxn);
    return 0;
}

Soda Machine 最多喂多少头牛 √

Soda Machine

题目描述

在这里插入图片描述
示例如上,大概思路是喂牛可以看成水平线,每头牛进食是一个区间,如上图所示第一头牛a进食区间[3,5],第二头牛b进食区间[4,8],第三头牛c进食区间[1,2],第四头牛d进食区间[5,10],其中soda machine安装在整数点上,可以看到安装在5位置处,最多有三头牛可以喂到。
输入一个N表示有N头牛,接下来N行,每行两个数表示该牛的进食区间,求放在哪可以喂最多的牛?
在这里插入图片描述

解析
和上述题目一样用差分来做

代码实现

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000000000;
int n;
map<int, int> diff;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int l,r;
        scanf("%d%d", &l, &r);
        diff[l] = diff[l] + 1;
        diff[r+1] = diff[r+1] - 1;
    }
    int sum = 0, maxn = 1;
    for (auto & p : diff) {
        sum += p.second;
        maxn = max(maxn, sum);
    }
    printf("%d\n", maxn);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在MATLAB中,NURBS(非均匀有理B样条)是一种强大的数学工具,用于表示和处理复杂的曲线和曲面。NURBS在计算机图形学、CAD(计算机辅助设计)、CAM(计算机辅助制造)等领域有着广泛的应用。下面将详细探讨MATLAB中NURBS的绘制方法以及相关知识点。 我们需要理解NURBS的基本概念。NURBS是B样条(B-Spline)的一种扩展,其特殊之处在于引入了权重因子,使得曲线和曲面可以在不均匀的参数空间中进行平滑插值。这种灵活性使得NURBS在处理非均匀数据时尤为有效。 在MATLAB中,可以使用`nurbs`函数创建NURBS对象,它接受控制点、权值、 knot向量等参数。控制点定义了NURBS曲线的基本形状,而knot向量决定了曲线的平滑度和分布。权值则影响曲线通过控制点的方式,大的权值会使曲线更靠近该点。 例如,我们可以使用以下代码创建一个简单的NURBS曲线: ```matlab % 定义控制点 controlPoints = [1 1; 2 2; 3 1; 4 2]; % 定义knot向量 knotVector = [0 0 0 1 1 1]; % 定义权值(默认为1,如果未指定) weights = ones(size(controlPoints,1),1); % 创建NURBS对象 nurbsObj = nurbs(controlPoints, weights, knotVector); ``` 然后,我们可以用`plot`函数来绘制NURBS曲线: ```matlab plot(nurbsObj); grid on; ``` `data_example.mat`可能包含了一个示例的NURBS数据集,其中可能包含了控制点坐标、权值和knot向量。我们可以通过加载这个数据文件来进一步研究NURBS的绘制: ```matlab load('data_example.mat'); % 加载数据 nurbsData = struct2cell(data_example); % 转换为cell数组 % 解析数据 controlPoints = nurbsData{1}; weights = nurbsData{2}; knotVector = nurbsData{3}; % 创建并绘制NURBS曲线 nurbsObj = nurbs(controlPoints, weights, knotVector); plot(nurbsObj); grid on; ``` MATLAB还提供了其他与NURBS相关的函数,如`evalnurbs`用于评估NURBS曲线上的点,`isoparm`用于生成NURBS曲面上的等参线,以及`isocurve`用于在NURBS曲面上提取特定参数值的曲线。这些工具对于分析和操作NURBS对象非常有用。 MATLAB中的NURBS功能允许用户方便地创建、编辑和可视化复杂的曲线和曲面。通过对控制点、knot向量和权值的调整,可以精确地控制NURBS的形状和行为,从而满足各种工程和设计需求。通过深入理解和熟练掌握这些工具,可以在MATLAB环境中实现高效的NURBS建模和分析。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值