三元组[01 Trie计数]

也许更好的阅读体验

Description\mathcal{Description}

在这里插入图片描述

Solution\mathcal{Solution}

有两种方法都可以拿到满分

Solution 1Solution\ 1

考虑枚举yy
建两个01Trie01Trie,要支持删除操作
一颗TrieTrie维护yy左边的信息
一颗TrieTrie维护yy右边的信息
在枚举yy的时候左边的添加,右边的删除,可做到loglog维护,建树是nlognlog
暴力的想法是两个TrieTrie一起跑,枚举在哪一位开始不一样,前面的情况也都枚举,这样的情况最坏是22的指数级别,可以拿到5050
考虑优化这个过程
因为每次只会删去一条链,所以考虑这条链被删去所带来的影响
f[i][0/1]f[i][0/1]表示到第ii位开始不一样的答案
每次删除时只少了一条链,所以把这条链的情况减去
增加时加上新的情况即可

Solution 2Solution\ 2

这种方法相对来说代码量要少很多
考虑枚举zz
用一颗TireTire表示前面的信息
仍然考虑枚举在哪一位开始不一样(d)(d)
s[i][0/1]s[i][0/1]表示前面所有在第ii位为0/10/1的串的总数
sum[i]sum[i]表示TireTireii号节点有多少个不合法的(x,y)(x,y)(y<x)(y<x)
cnt[i]cnt[i]表示TireTire上经过ii的个数
由于枚举的是zz,我们对yy的要求只有 枚举到dd时,其在dd00还是11
假设枚举到的zz的值在dd位是cc
答案就是cnt[原本串中和zzdd前面的位相同]×s[d][!c]\times s[d][!c]-不合法的(x,y)(x,y)对数
具体可看代码

Code\mathcal{Code}

Solution 2Solution\ 2
因为这种好实现些,所以就写的这种

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月23日 星期一 19时48分07秒
*******************************/
#include <cstdio>
#include <fstream>
#include <cstring>
#define ll long long
#define reset(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn = 3000006;
const int lim = 29;
//{{{cin
struct IO{
	template<typename T>
	IO & operator>>(T&res){
		res=0;
		bool flag=false;
		char ch;
		while((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
		while(ch>='0'&&ch<='9')	res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
		if (flag)	res=~res+1;
		return *this;
	}
}cin;
//}}}
int T,n,v,tot;
int ch[maxn][2],s[lim+1][2];
ll sum[maxn],cnt[maxn];
void insert (int rt,int v,int d)
{
	if (d<0)	return;
	int c=(v>>d)&1;
	if (!ch[rt][c])	ch[rt][c]=++tot;
	rt=ch[rt][c];
	++cnt[rt],sum[rt]+=++s[d][c];
	insert(rt,v,d-1);
}
ll query (int rt,int v,int d)
{
	if (d<0)	return 0;
	int c=(v>>d)&1,p=ch[rt][c^1];
	return cnt[p]*s[d][c^1]-sum[p]+query(ch[rt][c],v,d-1);
}
int main()
{
	cin>>T;
	while (T--){
		cin>>n;
		ll ans=tot=0;
		reset(sum),reset(s),reset(ch),reset(cnt);
		for (int i=1;i<=n;++i){
			cin>>v;
			insert(0,v,lim);
			ans+=query(0,v,lim);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章