Kanade's trio 2017多校#3 trie
求数组中i<j<k 并且ai^aj<aj^ak的三元组组数
枚举插入ak,让ak中每一位作为最高位,查找字典树内最高位不同的数字数量
注意把ak的每个前缀做一个bad标记
存储让这个前缀作为i可以与字典树内形成i,j对的个数,这些不满足i<j
ai : 1 1 0 1
aj : ? 0 0 0
ak : 1 0 0 1
结合这个图会直观点。。
#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; #define ll long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) const int inf=0x3f3f3f3f; const int maxn=5e5+9; struct NODE{ int cnt; int nxt[2]; int bad; }trie[maxn*30]; int sz; int dig[30]; int cnt[30][2]; ll ans; int arr[maxn]; void cal(int p,int cnt){ ans+=1ll*trie[p].cnt*(trie[p].cnt-1)>>1; //ai,aj都在前缀内选 ans+=1ll*trie[p].cnt*(cnt-trie[p].cnt)-trie[p].bad; //ai在前缀,aj不在 } void insert(){ int now=0; for(int i=0;i<30;i++){ if(!trie[now].nxt[dig[i]]){ trie[now].nxt[dig[i]]=++sz; } if(trie[now].nxt[1-dig[i]]){ cal(trie[now].nxt[1-dig[i]],cnt[i][1-dig[i]]); } now=trie[now].nxt[dig[i]]; trie[now].cnt++; trie[now].bad+=cnt[i][dig[i]]-trie[now].cnt; } } int main(){ int T; scanf("%d",&T); while(T--){ memset(trie,0,sizeof trie);memset(cnt,0,sizeof cnt); int n;scanf("%d",&n); sz=0,ans=0; FOR(n){ scanf("%d",&arr[i]); for(int j=29;j>=0;j--){ dig[j]=arr[i]%2;cnt[j][arr[i]%2]++;arr[i]/=2; } insert(); } printf("%lld\n",ans); } }学了字典树基本没用过。。
接着补题之前做做异或题吧。。