题目链接:http://www.ybtoj.com.cn/contest/123/problem/1
给出3个长度为n的排列A,B,C。然后一个下标集合S的三元组是
(max{Ai},max{Bi},max{Ci})(i∈S)
求所有下标集合不同的三元组数量
1≤n≤105
所有下标集合的三元组都能用一个|S|≤3的集合代替,所以我们只考虑|S|≤3的就好了。
|S|=1的个数就是n,直接累加即可。
|S|=2的话,那就代表某个下标霸占了两个最大值,而另一个一定是另一个下标的,如果是a,b最大,那么我们就要找满足ai>aj,bi>aj,ci<cj的方案,用三维偏序就好了。
然后a,c和b,c的情况也都要做
|S|=3的话很麻烦,考虑容斥,总方案(n3)减去有一个下标是至少两个的最大值。
同样和上面,先考虑a,b,假设下标i满足ai>aj,bi>bj的情况有k种,那么就好有(k2)种情况使得i占据了至少两个最大值。
同理a,c和b,c也要做,这是二维偏序,直接树状数组就好了。
但是发现对于i占据了三个最大值的情况我们统计了三次,需要加回多余的两次,那么统计ai>aj,bi>bj,ci>cj的个数k,然后加回k(k−1)的方案就好了,这个也要三维偏序
代码里三维偏序用的是CDQ分治+树状数组
时间复杂度O(nlog2n)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=1e5+10;
struct node{
ll a,b,c;
}w[N],a[N],b[N];
ll n,ans,sum,t[N],g[N];
void Change(ll x,ll val){
while(x<=n){
t[x]+=val;
x+=lowbit(x);
}
return;
}
ll Ask(ll x){
ll ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
void Merge(ll l,ll mid,ll r){
ll p=l,q=mid+1;
for(ll i=1;i<=r-l+1;i++){
if(p<=mid&&w[p].b<=w[q].b||q>r)b[i]=w[p],p++;
else b[i]=w[q],q++;
}
for(ll i=1;i<=r-l+1;i++)w[l+i-1]=b[i];
return;
}
void CDQ(ll l,ll r,bool op){
if(l==r)return;
ll mid=(l+r)>>1;
CDQ(l,mid,op);CDQ(mid+1,r,op);
ll p=l,tmp;
for(ll i=mid+1;i<=r;i++){
while(p<=mid&&w[p].b<w[i].b)
Change(w[p].c,1),p++;
sum+=(tmp=Ask(w[i].c));
g[w[i].a]+=(op?tmp:0);
}
for(ll i=l;i<p;i++)Change(w[i].c,-1);
Merge(l,mid,r);return;
}
bool cmp(node x,node y)
{return x.a<y.a;}
void solve(){
sort(w+1,w+1+n,cmp);
for(ll i=1;i<=n;i++){
ll tmp=Ask(w[i].b);
ans-=tmp*(tmp-1)/2;
Change(w[i].b,1);
}
memset(t,0,sizeof(t));
return;
}
signed main()
{
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
scanf("%lld",&n);ans=n;
for(ll i=1;i<=n;i++)scanf("%lld",&a[i].a);
for(ll i=1;i<=n;i++)scanf("%lld",&a[i].b);
for(ll i=1;i<=n;i++)scanf("%lld",&a[i].c);
for(ll i=1;i<=n;i++)
w[i].a=a[i].a,w[i].b=a[i].b,w[i].c=n-a[i].c+1;
sort(w+1,w+1+n,cmp);CDQ(1,n,0);
for(ll i=1;i<=n;i++)
w[i].a=a[i].a,w[i].b=a[i].c,w[i].c=n-a[i].b+1;
sort(w+1,w+1+n,cmp);CDQ(1,n,0);
for(ll i=1;i<=n;i++)
w[i].a=a[i].b,w[i].b=a[i].c,w[i].c=n-a[i].a+1;
sort(w+1,w+1+n,cmp);CDQ(1,n,0);
ans+=sum;ans+=n*(n-1)*(n-2)/6;
for(ll i=1;i<=n;i++)w[i].a=a[i].a,w[i].b=a[i].b;solve();
for(ll i=1;i<=n;i++)w[i].a=a[i].b,w[i].b=a[i].c;solve();
for(ll i=1;i<=n;i++)w[i].a=a[i].a,w[i].b=a[i].c;solve();
for(ll i=1;i<=n;i++)
w[i].a=a[i].a,w[i].b=a[i].b,w[i].c=a[i].c;
sort(w+1,w+1+n,cmp);
CDQ(1,n,1);
for(ll i=1;i<=n;i++)ans+=g[i]*(g[i]-1);
printf("%lld\n",ans);
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构