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;
}
如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.