gmoj 6829. 【2020.10.25提高组模拟】异或

Description

Input

Output

一行一个整数,表示满足条件的子序列的个数除以 998 244 353 的余数。

Sample Input

Sample Input1
3 0
0 1 2

Sample Input2
3 2
0 1 2

Sample Input3
3 3
0 1 2

Sample Input4
7 4
11 5 5 8 3 1 3

Sample Output

Sample Output1
7

Sample Output2
5

Sample Output3
4

Sample Output4
35

Data Constraint

Solution

对于30%的数据,我们可以求证\(min(a\oplus b,b \oplus c)\leqslant a \oplus c(a<b<c)\)

得到这个后,我们就可以对a数组进行排序

\(f_i\)为以\(a_i\)结尾的方案数

\(f_i=1+\sum_{1\leqslant j<i,a_i \oplus a_j\geqslant x}f_j\)

时间复杂度\(O(n^2)\)

对于100%的数据,我们考虑用trie来维护

把前i-1个数拆成60位从高位到低位塞进trie内

trie中维护的是对于\(a_i\)的方案数

则可以在log的时间里在trie中统计到答案

Code

#include <cstdio>
#include <algorithm>
#define MO 998244353
#define N 30000001
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int n,i,j,len,f[N],l[61],s[61],son[N][2];
long long x,ans,tot,a[N],tree[N];
bool bz[N];
void dg(int x,int y)
{
	if (y>60) 
	{
		(tot+=tree[x])%=MO;
		return;
	}
    if (s[y])
    {
        if (bz[son[x][l[y]^1]]) dg(son[x][l[y]^1],y+1);
    }else 
    {
        if (bz[son[x][l[y]^1]]) (tot+=tree[son[x][l[y]^1]])%=MO;
        if (bz[son[x][l[y]]]) dg(son[x][l[y]],y+1);
    }
}
void cha(int s[61],long long x)
{
    int tot=0;
    while (x)
    {
        tot++;
        s[60-tot+1]=x%2;
        x/=2;
    }
}
void ad(int x,int y)
{
    if (y>60) 
    {
        (tree[x]+=tot)%=MO;
        return;
    }
    if (!son[x][l[y]]) son[x][l[y]]=++len;
	bz[son[x][l[y]]]=1; 
    ad(son[x][l[y]],y+1);
    tree[x]=tree[son[x][0]]+tree[son[x][1]];
}
int main()
{
    open("xor");
    scanf("%d%lld",&n,&x);
    for (i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    len=1;
    cha(s,x);
    sort(a+1,a+n+1);
    bz[1]=1;
    for (i=1;i<=n;i++)
    {
    	tot=1;
        cha(l,a[i]);
        dg(1,1);
        ad(1,1);
        (ans+=tot)%=MO;
    }
    printf("%d",ans);
    return 0;
}
posted @ 2020-10-28 21:04  Sport_River  阅读(74)  评论(0编辑  收藏  举报