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

P14262 [ROI 2015 Day1] 自动好友

题目传送门

我的博客-欢迎光顾

写了一个很另类的容斥。。。比其他dalao的做法复杂不少


(为了方便描述,如果 \(i,j\) 是一对潜在好友,我们就称 \((i,j)\) 是一对朋友对)

(以下的 \(a,b,c\) 均指题目中的三个属性)

首先我们可以枚举两个人并判断它们能否构成一组潜在好友。时间复杂度 \(O(n^2)\)

然后,我们注意到这个题值域很小。于是本人就想着,依次算出 \(a\) 相同而 \(b,c\) 不同的朋友对, \(b\) 相同而 \(a,c\) 不同的朋友对,以及 \(c\) 相同而 \(a,b\) 不同的朋友对。最终答案就是三个朋友对的个数相加(显然不会有重复统计的朋友对)。

求这三种朋友对的方法都差不多。下面我们展开说说如何求 \(a\) 相同而 \(b,c\) 不同的朋友对。(其余同理)

我们可以将原来的人按 \(a\) 属性从小到大排序,这样 \(a\) 相同的人一定是在一个连续区间内的。

如果本题只有两个属性(仍然要求只有一个属性相同),那我们可以考虑记录一下当前 \(a\) 相同的人的左端点编号 \(l\) ,以及一个桶 \(mpb_{i}\) ,记录a属性的值落在这个区间的基础上,b属性为i的人有几个

这样,我们从左往右遍历 \(i\)\(i\) 对答案的贡献就是 \(i-l-mpb_{b_{i}}\)

现在变成三个属性了,怎么办?这个时候容斥就闪亮登场了。

沿用刚才的思路,我们用三个桶,一个桶 \(mpb_{i}\) ,记录a属性的值落在这个区间的基础上,b属性为i的人有几个;一个桶 \(mpc_{j}\) ,记录a属性的值落在这个区间的基础上,c属性为j的人有几个;一个桶 \(mp_{i,j}\) ,记录a属性的值落在这个区间的基础上,b属性为i的人且c属性为j的人有几个

这样, \(i\) 前面 \(a\) 相同但不满足条件的人的数量 \(num\) 就是 \(mpc_{c{i}}+mpb_{b{i}}-mp_{b_{i},c_{i}}\)\(i\) 对答案的贡献就是 \(i-top-num\)

这样我们就能求 \(a\) 相同而 \(b,c\) 不同的朋友对了。同理处理另两种情况即可。

代码实现的时候注意,如果进入了一个新的区间,那么 \(l\) 应当重新赋值,且 你开的几个桶都要初始化为 0 。

\(mp\) 这个桶如果不开 \(a\) 属性的这一位,那每次进入新区间都要初始化,很容易 TLE 。这里我采用了一个空间换时间的策略,给 \(mp\) 数组新开 \(a\) 的一维,这样我们只需要在处理一个大情况前初始化即可。

代码:

P14262正解
#include<bits/stdc++.h>
#define int long long
using namespace std;inline int read(){int x=0,f=1;char c=getchar();while(c<48){if(c=='-') f=-1;c=getchar();}while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}inline void write(int x){if(x<0) putchar('-'),x=-x;if(x<10) putchar(x+'0');else write(x/10),putchar(x%10+'0');
}const int N=1e5+5;
const int M=105;
int n,ans,mp1[M],mp2[M],mp3[M],mp[M][M][M];
//mp1,mp2,mp3:等同于题解中的mpa,mpb,mpc 
struct sw{int b[4];
}a[N];inline bool cmp1(sw x,sw y){return x.b[1]<y.b[1];
}inline bool cmp2(sw x,sw y){return x.b[2]<y.b[2];
}inline bool cmp3(sw x,sw y){return x.b[3]<y.b[3];
}inline void solve(int id){//mp桶的初始化 for(int i=1;i<=100;i++){for(int j=1;j<=100;j++){for(int k=1;k<=100;k++){mp[i][j][k]=0;}}}if(id==1){int top=0;//top:等同于题解中的l sort(a+1,a+n+1,cmp1);for(int i=1;i<=n;i++){int x=a[i].b[1],y=a[i].b[2],z=a[i].b[3];if(a[i].b[id]!=a[i-1].b[id]){//不相同则进入新区间 for(int j=1;j<=100;j++){mp2[j]=mp3[j]=0;}top=i;//记录一下左端点 }else{int x=a[i].b[1],y=a[i].b[2],z=a[i].b[3];//桶题解 int num=mp2[y]+mp3[z]-mp[x][y][z];ans=ans+(i-top-num);}//更新一下桶 mp2[y]++;mp3[z]++;mp[x][y][z]++;}}if(id==2){//注释见上 int top=0;sort(a+1,a+n+1,cmp2);for(int i=1;i<=n;i++){int x=a[i].b[1],y=a[i].b[2],z=a[i].b[3];if(a[i].b[id]!=a[i-1].b[id]){for(int j=1;j<=100;j++){mp1[j]=mp3[j]=0;}top=i;}else{int num=mp1[x]+mp3[z]-mp[x][y][z];ans=ans+(i-top-num);}mp1[x]++;mp3[z]++;mp[x][y][z]++;}}if(id==3){//注释见上 int top=0;sort(a+1,a+n+1,cmp3);for(int i=1;i<=n;i++){int x=a[i].b[1],y=a[i].b[2],z=a[i].b[3];if(a[i].b[id]!=a[i-1].b[id]){for(int j=1;j<=100;j++){mp2[j]=mp1[j]=0;}top=i;}else{int x=a[i].b[1],y=a[i].b[2],z=a[i].b[3];int num=mp2[y]+mp1[x]-mp[x][y][z];ans=ans+(i-top-num);}mp2[y]++;mp1[x]++;mp[x][y][z]++;}}
}signed main(){n=read();for(int i=1;i<=n;i++){a[i].b[1]=read(),a[i].b[2]=read(),a[i].b[3]=read();}solve(1);solve(2);solve(3);printf("%lld",ans);return 0;
}

另,如果你有对拍的需求,也欢迎你用如下代码与你的正解对拍(即 \(O(n^2)\) 代码):

P14262暴力
#include<bits/stdc++.h>
#define int long long
using namespace std;inline int read(){int x=0,f=1;char c=getchar();while(c<48){if(c=='-') f=-1;c=getchar();}while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}inline void write(int x){if(x<0) putchar('-'),x=-x;if(x<10) putchar(x+'0');else write(x/10),putchar(x%10+'0');
}const int N=1e5+5;
int n,a[N],b[N],c[N];signed main(){n=read();for(int i=1;i<=n;i++){a[i]=read(),b[i]=read(),c[i]=read();}int ans=0;for(int i=1;i<=n;i++){for(int j=1;j<i;j++){if((a[i]==a[j]&&b[i]!=b[j]&&c[i]!=c[j])||(a[i]!=a[j]&&b[i]==b[j]&&c[i]!=c[j])||(a[i]!=a[j]&&b[i]!=b[j]&&c[i]==c[j])){ans++;}}}printf("%lld",ans);return 0;
}

如果你觉得这篇题解还不错的话,记得留下你的赞呀qwq

http://www.gsyq.cn/news/25630.html

相关文章:

  • win10 升级 win11 后时间更新失败
  • Hands on Deep Learning Chapter 3 线性神经网络
  • 超越技术范畴:低代码如何重塑企业数字文化
  • 详细介绍:1、手把手教你入门设计半桥LLC开关电源设计,LLC谐振腔器件计算
  • 十六天
  • 20251019
  • 【上青了】
  • [VIM] reverse multiple lines in VIM
  • Tuack 生成比赛题目 PDF 笔记
  • 4060显卡也能玩转AI改图!Flux.1 Kontext Dev GGUF版本超详细入门教程 - 实践
  • 提升生产力:8个.NET开源且功能强大的快速开发框架
  • 使用c++14标准实现函数注册包装
  • 【VSCode中Java创建环境安装的三个层级之Maven篇】(Windows版)
  • 2025年不锈钢酸洗钝化液厂家推荐排行榜,环保型不锈钢管酸洗钝化液,不锈钢清洗钝化液,酸洗钝化处理工艺及不锈钢清洗剂公司推荐
  • 2025年法兰保护罩厂家推荐排行榜,阀门保温罩,法兰罩,法兰防溅罩,法兰保护套,专业防护与定制服务优质供应商
  • 百度网盘非会员下载慢怎么解决 - fosgrignonhto
  • d435i 标定 imu和相机 用来复现vins_fusion - 教程
  • K230基础-摄像头的使用 - 详解
  • 2025年市面上高杆灯品牌Top10权威推荐榜单
  • Spring AOP 原理
  • 250921
  • Jvm参数分类
  • 10/20
  • 2025年市面上工程石材产品排名前十:选购指南与品牌深度解析
  • 2025年市面上工程石材产品排名前十:权威榜单与选择指南
  • 听说今年很多应届硕士很难找到工作...
  • 开源 C++ QT QML 创建(四)复杂控件--Listview
  • 意大利居留 办理 看小红书上的材料就行,部分材料可以到按手印再补交
  • 博客的意義
  • 我写过的动态规划问题的状态表示与转移汇总