当前位置: 首页 > news >正文

蓝桥杯拔河,考察双指针,前缀和,区间处理

 这题解法很多,但是值得学习的我觉得还是双指针。数据可能爆炸所以建议开long long

代码

#include <bits/stdc++.h>
using namespace std;
long long rest=100000000;
long long abss(long long a,long long b)
{
  long long fin=a>b?a-b:b-a;
  return fin;
}
long long minn(long long a,long long b)
{
 long long fin=a>b?b:a;
 return fin;
}
int main()
{
  //双指针思路,定义l,r。l代表右队伍的左边界,r代表左队伍的右边界,每次判断左右队伍的和,那边少就在那边加入新的同学
    int n;
    cin>>n;
    long long a[1024]={0};
    for(int i=1;i<n;i++)
    {
      cin>>a[i];
    }
  // 枚举区间
  for(int i=0;i<n-1;i++)
  {
    for(int j=i+1;j<n;j++)
    {
      rest=minn(rest,abss(a[j],a[i]));//初始都只有一个先判断一下,防止一开始就是最小值,加不加都可以,加了更严谨
      long long minr=a[i];//设置左右两边的力量总和
      long long minl=a[j];
      int ll=i-1;
      int rr=j+1;设置边界条件,这里开始要进行差值判断了
      while(ll>=0&&rr<n)//开始进行人数的加入,因为要获取最小的差值,所以遍历所有可能
      {
        //判断那边人更少,要保证人数连续,而且差值最小,所以要判断左边加还是右边加,
        //其实就是遍历所有最小差值的可能性。
      if(minr<minl)
      {
        minr+=a[ll];
        ll--;
      }
      else
      {
        minl+=a[rr];
        rr++;
      }
      rest=minn(rest,abss(minl,minr));//每次判断完都要进行差值判断
      }
       //当一边枚举完另一遍没有的时候,将另一边枚举完
        
        while(ll>=0)
        {
          minr+=a[ll];
          ll--;
          rest=minn(rest,abss(minl,minr));
        }
        while(rr<n)
        {
            minl+=a[rr];
            rr++;
            rest=minn(rest,abss(minl,minr));
        }
    }
  }
//最后建议取整函数和取最小值函数建议自己写,因为数据要开long long 而自带的min函数和abs函数返回类型是int会报错。可能强制转换可以实现吧,但我没想过。
  cout<<rest;
  return 0;
}

思路在题目中,还有一个暴力解法和前缀和,

为了方便理解我说一个四重暴力

for    左边团队的左边界
    for    左边团队的右边界
        for    右边团队的左边界
            for    右边团队的右边界
                    每次取不同的区间,最后在进行差值判断。
其他两种方法都是在优化

     暴力满分题解

#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=1e3+10;
int n,js=1,a[N],check[N*N];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++){//我们先通过二层循环,暴力出每一种选法
        int s=0;
        for(int j=i;j<=n;j++){
            s+=a[j];
            check[js++]=s;
        }
    }//可能有谁都不选的选法,check数组从0开始
    sort(check,check+js);
    //将他们从小到大排序,力量值之和差距最小的一定是相邻的两种选法
    //不用管区间选择重叠的情况,重叠部分相当于两种选法都没选重叠部分
    int ans=1e12+10;
    for(int i=1;i<js;i++)ans=min(ans,check[i]-check[i-1]);
    cout<<ans;
    return 0;
}

简单解释一下

  for(int i=1;i<=n;i++){//我们先通过二层循环,暴力出每一种选法
        int s=0;
        for(int j=i;j<=n;j++){
            s+=a[j];
            check[js++]=s;
        }

这串代码的意思是将所有区间记录下来,对所有区间排序后,对于区间重复可以忽略因为,因为两者都有,可以都不要。排序后差值最小的应该是相邻的。其实这个考察的就是前缀和,加区间处理。

另一种解法就是利用前缀和来优化

 set<int> s;
for(int i = 1;i<=n;i++) {
        cin>>a[i];
        a[i]+=a[i-1];//构造前缀和
    }
    for(int i = 1;i<=n;i++){
        for(int j = i;j<=n;j++){
            s.insert(a[j]-a[i-1]);//枚举右区间所有情况先加入set中
        }
    }

上面用的map容器原理,下面这个用的set,其实对于重复的区间我们可以不考虑,但也不影响,

好处是set容器自动去重,减少时间复杂度。

下面是原版的代码,但是我觉得完全没有必要,去考虑区间重合问题,但是放出来学习一下。

#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
using namespace std;
#define ll long long
struct interval
{
    ll value, l, r;
};
vector<ll>v, v_sum;
vector<interval> v_sum_interval;
ll n, a1, sum = 0, min_distance = numeric_limits<ll>::max(), k1, a2 = 0;
interval kk;
int main() {
    cin >> n;
    v_sum.push_back(0);
    for (ll i1 = 0; i1 < n; i1++) {
        cin >> a1;
        sum += a1;
        v_sum.push_back(sum);
        v.push_back(a1);
    }
    for (ll i1 = 1; i1 <= n; i1++) {
        for (ll i2 = 0; i2 < i1; i2++) {
            kk.value = v_sum[i1] - v_sum[i2],kk.l=i2+1,kk.r=i1;
            v_sum_interval.push_back(kk);
        }
    }
    sort(v_sum_interval.begin(), v_sum_interval.end(), [](const interval& i1,const interval& i2) {return i1.value < i2.value; });
    for (ll i1 = 0; i1 < v_sum_interval.size() - 1; i1++) {
        if (v_sum_interval[i1 + 1].l > v_sum_interval[i1].r||v_sum_interval[i1 + 1].r < v_sum_interval[i1].l)
            min_distance = min(min_distance, v_sum_interval[i1 + 1].value - v_sum_interval[i1].value);
    }
    cout << min_distance;
}

相关文章:

  • 磁盘备份与系统封装
  • CentOS高性能数据处理优化指南
  • 搞定python之八----操作mysql
  • maven使用install将jar包编译到本地仓库管理
  • 从Scaling Laws中解析大模型训练的边际递减临界点
  • 【GPT入门】第20课 文心千帆注册与API调用
  • 单个及批量上传文件和文件夹思路——AntDesign
  • LeetCode 124.二叉树中的最大路径和
  • 深度学习与传统算法在人脸识别领域的演进:从Eigenfaces到ArcFace
  • 线性表的顺序表示
  • QuecPython + MQTT:物联网设备通信实战指南
  • 解决前端文字超高度有滚动条的情况下padding失效(el-scrollbar)使用
  • 鸿蒙跳转到系统设置app界面
  • 虚幻基础:GAS
  • ngx_http_module_t
  • Java调用Oss JDk删除指定目录下的所有文件
  • 【最大异或和——可持久化Trie】
  • 设计模式-桥接模式
  • C语言文件管理详解(上)
  • 下拉菜单+DoTween插件
  • 构建菌株有效降解有机污染物,上海交大科研成果登上《自然》
  • 央行:当前我国债券市场定价效率、机构债券投资交易和风险管理能力仍有待提升
  • 最快3天开通一条定制公交线路!上海推出服务平台更快响应市民需求
  • 汪海涛评《线索与痕迹》丨就虚而近实
  • 李云泽:小微企业融资协调工作机制已发放贷款12.6万亿元
  • 国际上首次,地月空间卫星激光测距试验在白天成功实施