2017多校联合第三场/hdu6059 Kanade's trio(tire tree)

来源:互联网 发布:阿里云 vs aws 编辑:程序博客网 时间:2024/06/07 04:10

Kanade's trio

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1079    Accepted Submission(s): 398


Problem Description
Give you an array A[1..n],you need to calculate how many tuples (i,j,k) satisfy that (i<j<k) and ((A[i] xor A[j])<(A[j] xor A[k]))

There are T test cases.

1T20

1n5105

0A[i]<230
 

Input
There is only one integer T on first line.

For each test case , the first line consists of one integer n ,and the second line consists of n integers which means the array A[1..n]
 

Output
For each test case , output an integer , which means the answer.
 

Sample Input
151 2 3 4 5
 

Sample Output
6
 

Source
2017 Multi-University Training Contest - Team 3
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  6181 6180 6179 6178 6177 
 

Statistic | Submit | Discuss | Note

题意

给出A[1..n](1<=n<=5105)(0<=A[i]<230),要求统计三元组(i,j,k)的个数使其满足i<j<k并且(A[i]xorA[j])<(A[j]xorA[k])

思路

事先把所有数字插入字典树中,用字典树维护A[k]的信息,接着对每一个A[i],枚举其二进制最高位小于A[k]的位数,考虑这样一个情况:若当前枚举到了A[i]的二进制第5位比A[k]小,那么A[i]A[k]的第30位到第6位都是相同的,此时就不用考虑A[j]的第30位到第6位如何,只考虑第5位的情况就好。 
考虑当前位置A[i]的情况,若当前位置A[i]为0,那么A[j]的相同位置要为0才能使两者异或值为0,此时A[k]为1,这时满足条件的A[j]A[k]对数可以计入答案。当前位置A[i]为1的情况同理(A[j]为1,A[k]为0)。

对于A[j]A[k]对数的统计,在插入A[k]时,之前插入的数就都成了A[j]。因此用一个cnt[i][j]数组记录下第i位为j的数之前出现了几次,那么在插入时,对于这一位置A[k]为0的情况,之前有多少的A[j]在这一位为1,就是此时满足条件的A[j]的个数。代码里的cnt[i][nxt ^ 1]就是此时符合条件的A[j]个数。

当我们把一个数从字典树中去掉时,也要考虑去掉这个数留下来的统计值。 
这题特殊的地方在于,插入是连续的,之后是连续的删除,所以在插入完成后可以把cnt[i][j]数组清空一遍,用来记录第i位为j的数被删除了几次。 
考虑两个方面: 
一个是这个数作为A[k]直接被去掉带来的影响,像之前一样减去其前面已经被删去的A[j]的个数(依然是cnt[now][nxt ^ 1])就好。(这一步操作在Trie::Insert()里面,与插入时的操作类似) 
还有一个是这个数作为A[j]带来的影响,因为这个数已经不能和后面的A[k]组合产生贡献了,考虑到在统计时,当前位的A[k]已经把可以与其组合的A[j]个数统计在了sum[tmp]中,这里面还需去掉被删去的A[j],被删去的A[j]已经被统计在了cnt[i][nxt]中,现有的A[k]被存在了val[tmp]中,这一部分不能被计入答案,相乘,减去。(sum[tmp] - val[tmp] * cnt[i][nxt]这一步在函数solve()里)

#include <iostream>#include <algorithm>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <string.h>#include <map>#include <set>#include <queue>#include <deque>#include <list>#include <bitset>#include <stack>#include <stdlib.h>#define lowbit(x) (x&-x)#define e exp(1.0)#define eps 1e-8//ios::sync_with_stdio(false);//    auto start = clock();//    cout << (clock() - start) / (double)CLOCKS_PER_SEC<<endl;typedef long long ll;typedef long long LL;using namespace std;typedef unsigned long long ull;const int maxn=5e5+10;ll a[maxn];int bits[32];struct tire{    int tot,root;    int val[maxn*30],ch[maxn*30][2];    ll sum[maxn*30],cnt[maxn][2];    int newnode()    {        val[tot]=sum[tot]=0;        ch[tot][0]=ch[tot][1]=-1;        return tot++;    }    void init()    {        tot=0;        root=newnode();        memset(cnt,0,sizeof(cnt));    }    void insert(int x,int v)    {        int now=root,nxt;        for(int i=30;i>=0;i--)        {            nxt=!!(x & bits[i]);            if(ch[now][nxt]==-1)                ch[now][nxt]=newnode();            now=ch[now][nxt];            cnt[i][nxt]++;            sum[now]+=v*cnt[i][nxt^1];            val[now]+=v;        }    }    ll solve(int x)    {        ll ret=0;        int now=root,tmp,nxt;        for(int i=30;i>=0;--i)        {            nxt=!!(x & bits[i]);            tmp=ch[now][nxt^1];            now=ch[now][nxt];            if(tmp!=-1)                ret+=sum[tmp]-val[tmp]*cnt[i][nxt];            if(now==-1) break;        }        return ret;    }}tire;int n;int main(){    ios::sync_with_stdio(false);    int T;    cin>>T;    bits[0]=1;    for(int i=1;i<32;i++)        bits[i]=bits[i-1]<<1;    while(T--)    {        cin>>n;        for(int i=1;i<=n;i++)            cin>>a[i];        ll ans=0;        tire.init();        for(int i=1;i<=n;i++)            tire.insert(a[i],1);        memset(tire.cnt,0,sizeof(tire.cnt));        for(int i=1;i<=n;i++)        {            tire.insert(a[i],-1);            ans+=tire.solve(a[i]);        }        cout<<ans<<endl;    }    return 0;}
原创粉丝点击