ABC392
终于进前一千了。
A - Shuffled Equation
人话:给定三个数 \(a,b,c\),判断是否存在两个数乘积为第三个数。
数很小,if 判断一下,long long 也不用开。
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int a,b,c;
int main(){
cin>>a>>b>>c;
if(a*b==c)cout<<"Yes"<<endl;
else if(b*c==a)cout<<"Yes"<<endl;
else if(c*a==b)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
时间复杂度 \(O(1)\)。
B - Who is Missing?
注意到值域很小,我们开一个桶。如果 \(i\) 出现过,则 \(f_i\) 为 \(1\),反之为 \(0\)。
然后按照 \(1\sim n\) 的顺序检查那个桶里没数就行。
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int n,m,x,t[1005],cnt;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>x,t[x]++;
for(int i=1;i<=n;i++)if(!t[i])cnt++;
cout<<cnt<<endl;
for(int i=1;i<=n;i++)if(!t[i])cout<<i<<" ";
return 0;
}
时间复杂度 \(O(n)\)。
C - Bib
挺绕的。
每个人有三个属性,编号,牌子(也就是 \(p_i\)),看的人的编号(也就是 \(q_i\))。
假设 \(s_i\) 表示牌子上的数位 \(i\) 的人的编号。这个可以预处理建立映射关系。
那么根据定义,牌子为 \(i\) 的人编号为 \(s_i\),看的人的编号为 \(q_{s_i}\),看的人挂的牌子为 \(p_{q_{s_i}}\)。
主要是搞清楚编号,牌子,看的人之间的关系即可。
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N=3e5+10;
int n,p[N],q[N],s[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",q+i);
}
for(int i=1;i<=n;i++){
scanf("%d",s+i);
p[s[i]]=i;
}
for(int i=1;i<=n;i++){
printf("%d ",s[q[p[i]]]);
}
return 0;
}
时间复杂度 \(O(n)\)。
D - Doubles
咋还卡人精度呢?
先思考暴力,枚举两个骰子 \(i,j\),枚举摇出来的数 \(x\),则答案就是:
\]
\]
\(cnt_{i,j}\) 表示骰子 \(i\) 有多少个面是 \(j\),上面的式子根据乘法原理和加法原理易得。
暴力会超时,注意值域很小,我们先枚举 \(i\),然后开一个桶 \(t_j\) 表示骰子 \(i\) 有多少个面为 \(j\)。
接着我们枚举每一个 \(j<i\),分别计算 \(i,j\) 的答案,具体做法是遍历 \(j\) 骰子的每一个面 \(x\),然后让答案 \(ans\) 加上 \(t_x\)。最后 \(\frac{ans}{k_ik_j}\)。
枚举 \(i\) 是 \(O(n)\) 的,枚举每一个骰子 \(i\) 的面是 \(K_i\),枚举 \(j\),枚举 \(j\) 骰子的每一个面可以看成一个整体,是 \(O(S-K_i)\) 的,其中 \(S=\sum K_i\),意思是最多会将除了骰子 \(i\) 以外其他所有骰子的所有面都遍历一遍。
容易发现后两步合起来是 \(O(S)\)。这样做复杂度均摊下来是正确的。
点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N=1e5+10;
vector<int>v[105];
int n;
long long k[105],cnt[N];
long double res,ans;
long double fmax(long double a,long double b){
return a<b?b:a;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",k+i);
for(int j=1,x;j<=k[i];j++){
scanf("%d",&x);
v[i].push_back(x);
}
}
for(int i=2;i<=n;i++){
for(auto u:v[i])cnt[u]++;
for(int j=1;j<i;j++){
res=0;
for(auto u:v[j])res=(double)(res+cnt[u]);
res=(long double)(res/(k[i]*k[j]));
ans=max(ans,res);
}
for(auto u:v[i])cnt[u]--;
}
printf("%.12LF\n",ans);
return 0;
}
时间复杂度 \(O(nS)\)。
E - Cables and Servers
小清新题。
注意到 \(M\ge N-1\),也就是说无论如何我们也可以给所有边的两个端点重新编号,让他联通。
我们先把原图建出来,这样的图是若干个不连通的图。在原图中,有一些边是无关紧要的,去掉这一条边对原图联通性没有影响。我们可以用这些边来连接其他的联通块。
我们思考这样一个过程:划分联通块,然后找出每个联通块有多少个无用的边,统计当前那个联通块 \(u\) 无用边最多,那个联通块 \(v\) 无用边次多,将 \(u\) 内的一条无用边的一个端点改到 \(v\) 上的端点,此时 \(u,v\) 就被合并了,\(v\) 的无用边也变成了 \(u\) 的无用边。因为 \(M\ge N-1\),所以除了这个图仅剩一个联通块的情况,无论何时都有无用边。
容易发现,此时 \(u,v\) 合并后的联通块又成为了无用边最多的联通块,假设有 \(k\) 个联通块,我们按照每个联通块内部无用边多少排序,然后依次将 \(2\sim k\) 的联通块和 \(1\) 合并,这个算法就是正确的,容易发现,这样的操作此时为 \(k-1\)。
考虑构造方案,我们把每个联通块排好序后,将每个联通块内的无用边按照同样顺序放进数组里,然后从前往后一条一条边的用即可。
点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=2e5+10;
int n,m,a[N],b[N],f[N],rt[N],k,rest[N],p,mk[N];
vector<int>vec[N];
int found(int x){
return f[x]==x?x:f[x]=found(f[x]);
}
bool cmp(int a,int b){
return vec[a].size()>vec[b].size();
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++){
scanf("%d %d",a+i,b+i);
int u=found(a[i]);
int v=found(b[i]);
if(u!=v)f[u]=v;
else mk[i]=1;
}
for(int i=1;i<=m;i++)if(mk[i])vec[found(a[i])].push_back(i);
for(int i=1;i<=n;i++)if(found(i)==i)rt[++k]=i;
printf("%d\n",k-1);
sort(rt+1,rt+1+k,cmp);
for(int i=1;i<=k;i++)for(auto j:vec[rt[i]])rest[++p]=j;
for(int i=2;i<=k;i++){
printf("%d %d %d\n",rest[i-1],a[rest[i-1]],rt[i]);
}
return 0;
}
时间复杂度 \(O(n\log n)\)。
F - Insert
平衡树板子,蚌埠住了。
考虑无旋 treap(FHQ treap),每个节点上维护一个权值,和子树的大小,插入第 \(i\) 个数时,假设这个数排名为 \(k\)。split 时,将平衡树分成两颗大小分别为 \(k-1\) 和 \(i-k\) 两颗平衡树,merge 时把新建的节点夹在中间合并即可,时间复杂度 \(O(n\log n)\)。
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N=5e5+10;
int tot,root,n;
struct node{
int l,r,size,dat,val;
}a[N];
int New(int s){
a[++tot].val=s;
a[tot].size=1;
a[tot].dat=rand();
return tot;
}
void update(int p){
a[p].size=a[a[p].l].size+a[a[p].r].size+1;
}
void split(int p,int k,int &x,int &y){
if(!p)return x=y=0,void();
else if(a[a[p].l].size+1<=k)split(a[p].r,k-a[a[p].l].size-1,a[x=p].r,y);
else split(a[p].l,k,x,a[y=p].l);
update(p);
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(a[x].dat>a[y].dat)return a[x].r=merge(a[x].r,y),update(x),x;
else return a[y].l=merge(x,a[y].l),update(y),y;
}
void insert(int s,int k){
int x=0,y=0;
split(root,k-1,x,y);
root=merge(merge(x,New(s)),y);
}
void print(int p){
if(!p)return;
print(a[p].l);
printf("%d ",a[p].val);
print(a[p].r);
return;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int p;
scanf("%d",&p);
insert(i,p);
}
print(root);
return 0;
}
多的可以去看平衡树模板。
G - Fine Triplets
好好好,都会 FFT/NTT 是吧。
首先 \(B-A=C-B\) 可以写作 \(2B=A+C\),所以我们只需要求出有多少个数对 \((A,C)\) 和为 \(2B\)。
我们不妨开一个桶 \(t\),\(t_x\) 表示 \(S\) 中 \(x\) 的出现次数。记 \(m=2B\),上面说的这个问题答案即为 \(\sum_{i=1}^{m-1}t_it_{m-i}\) 的一半(因为求得是无序数对)。
这个玩意不就是一个卷积吗,FFT/NTT 可以 \(O(n\log n)\) 求出来。
?这不是卷积模板吗。
好吧,我不会卷积。。。
随机推荐
- c#实现 正弦sin、反正弦arcsin,正切tan、反正切arctan:求角度值
1 #region 三角函数和反三角函数 2 3 using System; 4 using System.Collections.Generic; 5 using System.IO; 6 usin ...
- 炸裂!!!Deepseek接入个人知识库,回答速度飞起来,确实可以封神了
高效管理知识.快速获取信息成为提升工作效率的关键.无论是做技术的同学还是普通的上班族,在日常积累了大量的知识数据和内容.项目文档.会议记录到技术手册.业务流程,这些信息如同宝藏一般,等待着被高效利用. ...
- 代码随想录第十一天 | Leecode 150. 逆波兰表达式求值、239. 滑动窗口最大值、347. 前k个高频词
Leecode 150. 逆波兰表达式求值 题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description ...
- <HarmonyOS第一课09>应用程序框架进阶#鸿蒙课程##鸿蒙生态#
课程介绍 本课程<应用程序框架进阶>旨在深入探讨应用程序框架的核心概念和高级特性.课程首先介绍应用程序框架的基本概念,确保学员对框架有全面的认识.接着,我们将深入探讨AbilityStag ...
- 【经验】Ubuntu 20.04 ROS2 Foxy安装
参考博客 ROS2安装 有的地方原博主打错了,还没改过来,我按我自己的改好了. 有的地方比如github和raw.githubusercontent.com访问不了,我替换成能用的镜像源了,只求一键复 ...
- 网络编程:阻塞I/O和线程模型
线程 进程模型在处理用户请求的过程中,进程切换上下文的代价比较高,而,一种轻量级的模型可以处理多用户连接请求,那就是线程模型. 线程(thread)是运行在进程中的一个"逻辑流", ...
- HarmonyOS NEXT开发教程:全局悬浮窗
今天跟大家分享一下HarmonyOS开发中的悬浮窗. 对于悬浮窗,可能有的同学会想到使用层叠布局是否可以实现,将悬浮窗叠在导航栏组件Tabs上,像这样: Stack({alignContent:Ali ...
- python实现字符输入实时读取
原理:通过opencv中的waitKey来实现 示例代码: def key_control(): while 1: cv2.imshow('tmp', np.zeros(shape=(100, 100 ...
- java后端开发小技巧-集合初始化多种方法
阅读说明: 1.如果有排版格式问题,请移步 <后端开发小技巧-java集合创建>,选择宽屏模式效果更佳. 2. 本文为原创文章,转发请注明出处. 后端开发中集合是经常会用到的类型.java ...
- 2025 年实用、全面的 VS Code 插件推荐!
前言 VS Code是一款由微软开源免费.轻量级.功能强大的源代码编辑器.其轻量级体现在基础安装简洁,仅含核心编辑功能.功能强大则源于它支持丰富的语言环境插件拓展,这种模块化设计让VS Code在源代 ...