当前位置: 首页 > 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.dtcms.com/a/291611.html

相关文章:

  • 微信二维码扫描登录流程详解
  • Pytorch版本、安装和检验
  • 简单讲解HTTPS如何保证安全性和可靠性
  • 网安学习NO.15
  • 树链剖分-苹果树
  • TPS61194PWPRQ1适用于汽车照明低 EMI、高性能 4 通道 LED 驱动器TPS61194
  • Day07_网络编程20250721_大项目
  • sqli-labs靶场通关笔记:第46-53关 order by注入
  • 一文详解REST风格
  • 青少年科学世界名刊分析评介:《生物技术世界》
  • 机器学习中的数据预处理:从入门到实践
  • Spring 对数组和集合类的自动注入
  • 234、回文链表
  • 使用AI把普通的条形柱状图,丰富成“好看高大上”的条形柱状图
  • 解决win10下Vmware虚拟机在笔记本睡眠唤醒后ssh连接不上的问题
  • PyQt5—QInputDialog 学习笔记
  • 印度给巴铁断水,中国悄然开建雅鲁藏布江水电站,纯属巧合!
  • Python 标准库之 os 模块全面讲解
  • 大模型为什么出现幻觉?
  • 在Anolis8.6上源码编译安装部署OpenVAS(GVM)未完待续
  • 华为云CCE-PV使用OBS存储类之坑
  • Android NDK ffmpeg 音视频开发实战
  • 语义化版本规范(SemVer)
  • 【计算机组成原理】符号位OF、ZF、CF、SF详解
  • c语言 进阶 动态内存管理
  • stream event
  • Playwright-MCP浏览器会话复用全解析
  • swiper js无缝滚动---解决播放总是有间隔、动画一闪一跳的问题
  • 3.组合式API父子通信
  • 【免费版】开启 Youtube 双语字幕