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

2025杭电多校赛(2)1006 半

题目整理

问题描述
某学校举办两场个人比赛,共有相同的 n 名选手(编号 1∼n)。已知两场比赛的排名结果:

  • 第一场排名:a1​,a2​,⋯,an​(从高到低)
  • 第二场排名:b1​,b2​,⋯,bn​(从高到低)

其中 a 和 b 均为 1∼n 的排列(无重复排名)。
作为选手 i,你可以通过禁赛其他选手,使得自己在两场比赛中均成为第一名。要求计算:对于每个选手 i,最少需要禁赛多少名选手
(禁赛后,剩余选手的相对排名保持原顺序不变)

输入格式

  • 第一行:整数 T(1≤T≤20),表示测试数据组数
  • 每组数据:
    • 第一行:整数 n(1≤n≤106)
    • 第二行:n 个整数 a1​,a2​,⋯,an​(第一场排名)
    • 第三行:n 个整数 b1​,b2​,⋯,bn​(第二场排名)
  • 总数据规模:所有测试数据的 n 之和不超过 2×106

输出格式

  • 每组测试数据输出一行:n 个整数,第 i 个整数表示选手 i 的最少禁赛人数

Sample Input

1

5

2 1 5 4 3

2 4 5 1 3

Sample Output

3 0 4 3 3

这题题意不难,就是找到一个数在两个数组中前面的数的集合的交集大小,而在这里我们要好好利用这两个数组是n的全排列的性质。

注意下面的代码是超时的,优化方法后面说。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,temp,a[1000005],b[1000005],n,ans[1000005];
set<int>arr;
int main() {
scanf("%d",&t);
while(t--){arr.clear();scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=n;i++){scanf("%d",&temp);b[temp]=i;}for(int i=1;i<=n;i++){arr.insert(b[a[i]]);int s1=i-distance(arr.begin(),arr.find(b[a[i]]))-1;int s2=b[a[i]]-1;ans[a[i]]=s1+s2; }for(int i=1;i<=n;i++){printf("%d ",ans[i]);}printf("\n");
}return 0;
}

解释:这里的a数组就是和题目的一样,而b数组记录的是数字为i的下标,这是为了利用全排列的性质。

1.我们从前向后遍历a数组,那么i-1就是这个数(now)前面有几个数。我们现在要确定这些数有几个在b数组的now的前面,也就是重复的。

2.我一开始用set来实现,每次就把遍历到的数now的在b数组的下标插入到set中,因为set会自动排序,而且下标是不会重复的。这样我们每次查询前面有几个数就是有几个重复的(我这样表述的不好),下面我讲线段树维护可能好懂一些。但是distance函数速度是n,我本以为是常数,这样就是n^2算法,和暴力没什么区别。

3.那只有用树状数组或线段树维护。我们要维护的实际是一个前缀和数组,而这个数组每次都要有一个数从0变为1,每次我们也都要查询一个特定的前缀和值。那这就是线段树的单点修改,区间查询。套用线段树模板就行。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{long long r,l,sum,lz;
};
node tree[5000005];
int t,temp,a[1000005],b[1000005],n,ans[1000005];
void init(){for(int i=1;i<=5000000;i++){tree[i].l=tree[i].lz=tree[i].r=tree[i].sum=0;}
}
void push_down(int i)//下传函数
{if(tree[i].lz!=0){tree[i*2].lz+=tree[i].lz;tree[i*2+1].lz+=tree[i].lz;tree[i*2].sum+=tree[i].lz*(tree[i*2].r-tree[i*2].l+1);tree[i*2+1].sum+=tree[i].lz*(tree[i*2+1].r-tree[i*2+1].l+1);tree[i].lz=0;}return;
}
void build(int i,int l,int r)//建树
{tree[i].l=l,tree[i].r=r;tree[i].lz=0;if(l==r){return;}int mid=(l+r)/2;build(2*i,l,mid);build(2*i+1,mid+1,r);
}
void add(int i,int l,int r,int k)//区间加减
{if(tree[i].l>=l&&tree[i].r<=r){tree[i].sum+=k*(tree[i].r-tree[i].l+1);tree[i].lz+=k;return;}push_down(i);if(tree[i*2].r>=l){add(i*2,l,r,k);}if(tree[i*2+1].l<=r){add(i*2+1,l,r,k);}tree[i].sum=tree[2*i].sum+tree[2*i+1].sum;return;
}
long long search(int i,int l,int r)//查询
{if(tree[i].l>=l&&tree[i].r<=r){return tree[i].sum;}if(tree[i].r<l||tree[i].l>r){return 0;}push_down(i);long long ans=0;if(tree[i*2].r>=l){ans+=search(i*2,l,r);}if(tree[i*2+1].l<=r){ans+=search(i*2+1,l,r);}return ans;
}
int main() {
scanf("%d",&t);
while(t--){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=n;i++){scanf("%d",&temp);b[temp]=i;}build(1,1,n);for(int i=1;i<=n;i++){add(1,b[a[i]],b[a[i]],1);ans[a[i]]=b[a[i]]-1+search(1,b[a[i]],n)-1;}for(int i=1;i<=n;i++){printf("%d ",ans[i]);}init();printf("\n");
}return 0;
}

http://www.lryc.cn/news/595452.html

相关文章:

  • 对称加密技术详解:原理、算法与实际应用
  • 代码随想录算法训练营二十二天|回溯part04
  • 关于线程的例子
  • 【力扣】第42题:接雨水
  • 复制docker根目录遇到的权限问题
  • 模拟高负载测试脚本
  • 闲庭信步使用图像验证平台加速FPGA的开发:第二十八课——图像膨胀的FPGA实现
  • 关于Ajax的学习笔记
  • Linux的相关指令
  • 「日拱一码」034 机器学习——插值处理
  • Unity 脚本生命周期详解与实战分析
  • (十九)深入了解 AVFoundation-编辑:使用 AVMutableVideoComposition 实现视频加水印与图层合成(上)——理论篇
  • iOS 加固工具有哪些?快速发布团队的实战方案
  • RIQ模型时间管理方法详解
  • 工业自动化中的协议转换:RS485转PROFIBUS网关在涡街流量计与S7-300 PLC通信中的应用
  • Swap Face 使用遇到的问题
  • Match宣布2025曼谷发布会,发布“保本”资管新范式,旨在重塑Web3投资规则
  • 20250720问答课题-基于BERT与混合检索问答系统代码解读
  • 企业开发转型 | 前端AI化数字化自动化现状
  • 自动化商品监控:利用淘宝API开发实时价格库存采集接口
  • 【unitrix】 6.11 二进制数字标准化模块(normalize.rs)
  • G7打卡——Semi-Supervised GAN
  • Acrobat JavaScript 中的 `app.response()` 方法
  • 【学习路线】C#企业级开发之路:从基础语法到云原生应用
  • 基于MySQL实现分布式调度系统的选举算法
  • 一文速通《矩阵的特征值和特征向量》
  • Tomcat的部署、单体架构、session会话、spring
  • PostgreSQL高可用架构Repmgr部署流程
  • 计算机网络中:传输层和网络层之间是如何配合的
  • socket编程(UDP)