标签:基中 2021.11 12NOIP int 基内 元素 异或 线性 联考
Description
\(\text{xyx}\) 是一个喜欢数数的触手怪。
他很喜欢异或!于是他摸出一个数列 \(\left\{a_{n}\right\}\)。 并在上面做了一番操作, 每次操作形如 \(a_{i}:=a_{i} \oplus a_{i-1}(1<i \leq n)\), 其中 \(\oplus\) 表示异或。
他想知道, 在任意次操作后, 他能从这个初始数列得到多少不同的数列。
Solution
比较结论的一道题目。
首先讲一个叫做线性基的东西,具体定义如下:
由一个集合构造出来的另一个集合,它有以下几个性质:
- 线性基的元素能相互异或得到原集合的元素的所有相互异或得到的值。
- 线性基是满足性质 1 的最小的集合。
- 线性基没有异或和为 0 的子集。
- 线性基中每个元素的异或方案唯一,也就是说,线性基中不同的异或组合异或出的数都是不一样的。
- 线性基中每个元素的二进制最高位互不相同。
那么线性基对这道题目有什么用呢?
想一下原序列的两个数异或,相当于在线性基内若干个异或起来的个数,也就是说,第 \(i\) 位置的答案就是在这之前,2 的线性基内元素个数次方,即线性基内元素个数为 \(x\),那么答案就是 \(2^x\)。
统计完 \(i\) 的答案后要将 \(a_i\) 插入线性基,插入线性基的方法这里不在赘述,读者可以自行搜索,这里给出插入的代码:
void insert(int x)
{
for (int i=30;i>=0;--i)
{
if (!(x&(1<<i))) continue;
if (!p[i])
{
p[i]=x;
++num;
break;
}
x^=p[i];
}
}
那么最后的答案就是 \(\Pi\ 2^x\)。
Code
#include<cstdio>
#define N 100005
#define mod 998244353
using namespace std;
int n,ans,num,a[N],p[31];
void insert(int x)
{
for (int i=30;i>=0;--i)
{
if (!(x&(1<<i))) continue;
if (!p[i])
{
p[i]=x;
++num;
break;
}
x^=p[i];
}
}
int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
ans=1;
for (int i=1;i<=n;++i)
{
ans=(ans*(long long)(1<<num)%mod)%mod;
insert(a[i]);
}
printf("%d\n",ans);
return 0;
}
标签:基中,2021.11,12NOIP,int,基内,元素,异或,线性,联考 来源: https://www.cnblogs.com/Livingston/p/15546278.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。