题解:AT_abc439_d [ABC439D] Kadomatsu Subsequence

枚举 \(j\)

  • \(j=\min(i,j,k)\),那么 \(i\) 应该满足 \(A_i=\dfrac{7A_j}{5}\)\(A_k=\dfrac{3A_j}5\),由于 \(i,j,k\) 各不相等,所以 \(i,k\in[j+1,n]\)
    • 此时贡献为 \([j+1,n]\)\(\dfrac{7A_j}{5}\) 这个数出现的次数乘上 \([j+1,n]\)\(\dfrac{3A_j}{5}\) 出现的次数。
  • 同理,\(j=\max(i,j,k)\) 时,就变成了 \([1,j-1]\) 内贡献。

怎么处理呢?

离线二维数点!(当然你用 cdq 也可以)

前置知识:P10814 【模板】离线二维数点

另外,这题不能用权值树状数组。

  1. 这题 \(V=10^9\),空间 \(O(V)\) 直接炸飞。
  2. 虽然可以,但其实不太方便离散化。

所以我们其实可以用平衡树维护,空间 \(O(n)\)

https://atcoder.jp/contests/abc439/submissions/72215221

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=3e6+10;
int cnt;
int root=0,k;
struct treap{
	int ls,rs;
	int val,pri;
	int cnt,size;
}t[maxn];
void up(int id){t[id].size=t[t[id].ls].size+t[t[id].rs].size+t[id].cnt;}
void zag(int &rt){//左旋
	int b=t[rt].rs;
	t[rt].rs=t[b].ls;
	t[b].ls=rt;
	up(rt);up(b);
	rt=b;
}
void zig(int &rt){//右旋
	int b=t[rt].ls;
	t[rt].ls=t[b].rs;
	t[b].rs=rt;
	up(rt);up(b);
	rt=b;
}
void insert(int &rt,int x){
	if(rt==0){
		t[++k].val=x;
		t[k].cnt=t[k].size=1;
		t[k].pri=rand()%1145140;
		rt=k;
		return;
	}
	t[rt].size++;
	if(x==t[rt].val){
		t[rt].cnt++;
		return;
	}
	if(x<t[rt].val){
		insert(t[rt].ls,x);
		if(t[t[rt].ls].pri<t[rt].pri)zig(rt);
	}
	else{
		insert(t[rt].rs,x);
		if(t[t[rt].rs].pri<t[rt].pri)zag(rt);
	}
}
int query(int rt,int x){
	if(rt==0)return 1;
	if(t[rt].val<=x)return t[t[rt].ls].size+t[rt].cnt+query(t[rt].rs,x);
	else return query(t[rt].ls,x);
}
struct qry{
	int r,type,x,id;
	friend bool operator<(qry aa,qry bb){
		return aa.r<bb.r;
	}
}b[maxn*9];
int a[maxn],tot=0,V=1e5+10,ans[maxn*2];
signed main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int j=1;j<=n;j++){
		if(a[j]%5)continue;
		int v=a[j]/5;
		int goi=v*7,gok=v*3;
		//现在需要知道 [1,j-1] 内 goi,gok 出现的次数
		//以及[j+1,n] 内 goi,gok 出现的次数
		b[++tot]={0,-1,goi,j};//[1,l-1]
		b[++tot]={j-1,1,goi,j};//[1,r]
		b[++tot]={j,-1,goi,j+n};//[1,l-1]
		b[++tot]={n,1,goi,j+n};//[1,r]
		b[++tot]={0,-1,gok,j+n*2};//[1,l-1]
		b[++tot]={j-1,1,gok,j+n*2};//[1,r]
		b[++tot]={j,-1,gok,j+n*3};//[1,l-1]
		b[++tot]={n,1,gok,j+n*3};//[1,r]
	}
	int k=1;
	sort(b+1,b+tot+1);
	for(int i=1;i<=tot;i++){
		while(k<=b[i].r)insert(root,a[k++]);
		ans[b[i].id]+=b[i].type*(query(root,b[i].x)-query(root,b[i].x-1));//ans=[1,r]-[1,l-1]
	}
	for(int j=1;j<=n;j++){
		if(a[j]%5)continue;
		cnt+=ans[j]*ans[j+n*2]+ans[j+n]*ans[j+n*3];
	}
	
	cout<<cnt;
	
	return 0;
} 

等一下!

这不是黄吗?

于是我们发现在枚举的过程中,就可以处理上面的内容了。但坏处是要枚举两遍。

用个 map 维护即可。

posted @ 2026-01-22 21:07  zhangruixiang  阅读(3)  评论(0)    收藏  举报