题意

给定三个整数 \(n,k,c\) 和一个长度为 \(n\) 的序列 \(a\),保证 \(a_i\) 互不相同。可以操作 \(k\) 次,每次随机选择一个 \(a_i\) 变成 \(a_i-1\)。问最后的序列异或和为 \(0,\cdots 2^{c}-1\) 的概率。

\(\texttt{Data Range:}k,c\leq 16,k\leq a_i\leq 2^c-1,n\leq 2^{c}-k\)

题解

先来看一个显而易见的结论:对于 \(x\leq 2^c-1\),本质不同的 \(k\) 元组 \((x\oplus(x-1),x\oplus(x-2),\cdots,x\oplus(x-k))\) 的个数大约是 \(O(ck)\) 的。

首先注意到 \(x\oplus(x-1)\) 这个东西的取值只能是 \(2^t-1\) 的形式,其中 \(t=\log\operatorname{lowbit}(x)+1\)。考虑分类讨论。

  • 如果 \(t>\log k\),因为 \(x\oplus (x-k)=(x\oplus (x-1))\oplus((x-1)\oplus(x-2))\cdots\),那么比 \(t\) 高的位不受影响,比 \(t\) 低的位因为是从 \(2^t-1\) 开始一个一个减的,与 \(x\) 无关,所有只有 \(O(c)\) 种取值。

  • 如果 \(t\leq\log k\),那么这东西的取值只与 \(\log k\) 位往上走第一个 \(1\) 的位置和这 \(\log k\) 位的取值相关,所以取值为 \(O(c2^{\log k})=O(ck)\) 的。

经暴力计算可得 \(c=k=16\) 的时候只有 \(192\) 种本质不同的 \(k\) 元组。

由于直接数不好数,这里我们考虑每一次操作怎么改变答案的。容易看出如果对 \(a_i\) 操作 \(j\) 次的话会给原来的答案异或上 \(a_i\oplus (a_i-j)\)。

这个时候可以数一下本质不同操作序列的个数。由于操作序列随机排列是本质相同的,所以需要使用 EGF。为了方便,这里设 \(d_{i,j}=a_i\oplus(a_i-j)\),那么位置 \(i\) 的 EGF 为

\[\sum\limits_{j=0}^{k}\frac{x^{d_{i,j}}y^j}{j!}
\]

这里 \(x\) 枚举的是这个位置的值,\(y\) 枚举的是操作次数。将每个位置的这些东西乘起来得到总共的 EGF:

\[F(x,y)=\prod_{i=1}^{n}\left(\sum\limits_{j=0}^{k}\frac{x^{d_{i,j}}y^j}{j!}\right)
\]

其中 \(x\) 这个维度为异或卷积,\(y\) 为加法卷积。那么 \(v![x^u][y^v]\) 就表示操作了 \(v\) 次之后使得答案为 \(u\oplus a_1\oplus\cdots\oplus a_n\) 的方案数。注意到操作顺序不影响操作结果,在 EGF 的过程中去掉了这个影响,在最后统计的时候要乘回来。

考虑如何简化计算。对于每一个本质不同的 \(k\) 元组 \((x\oplus(x-1),x\oplus(x-2),\cdots,x\oplus(x-k))\) 来说,它对应的 EGF 是 \(x\) 操作若干次之后对答案的影响。于是我们可以设 \(G_i(x,y)\) 为第 \(i\) 中本质不同的 \(k\) 元组对应的 EGF,\(r_i\) 为出现次数,于是也可以这么表示 \(F\):

\[F(x,y)=\prod_{i}G^{r_i}_i(x,y)
\]

这个时候如果采用 \(O(k^2)\) 暴力先 \(\ln\) 再 \(\exp\) 求快速幂的话复杂度为 \(O(2^cck^3)\)。如果使用牛顿迭代的话因为常数原因,而且多项式次数较小跑得还没有暴力快。

对于某个 \(k\) 元组来说,考虑钦定一个 \(y\),再对 \(x\) 这个维度做 FWT。因为钦定了 \(y\) 的话只会有一个 \(x\) 的系数是形如 \(\frac{y^k}{k!}\) 的。根据 FWT 的相关理论,做完 FWT 之后中每一项都是形如 \(\pm\frac{y^k}{k!}\) 的。

这个时候就可以将每一个 \(k\) 元组对应到一个 \(1\) 和 \(-1\) 的序列上去,这个序列可以状压。将状压之后的东西放在一起快速幂即可。

代码

#include<bits/stdc++.h>
#pragma GCC optimize("Ofast,unroll-loops")
#define pb emplace_back
#define popc __builtin_popcount
using namespace std;
typedef int ll;
typedef long long int li;
typedef vector<ll> vi;
const ll MAXN=65541,MOD=998244353;
map<vi,ll>mp;
ll n,kk,c,xorv,tot,fct,d,tp;
ll x[MAXN],invl[MAXN],finv[MAXN],f[MAXN],cnt[MAXN<<1];
ll st[201],sm[201],tmp[21],tmp2[21],tmp3[21];
li tmp4[21];
vi v[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline ll qpow(ll base,ll exponent)
{
ll res=1;
while(exponent)
{
if(exponent&1)
{
res=(li)res*base%MOD;
}
base=(li)base*base%MOD,exponent>>=1;
}
return res;
}
inline void ln(ll fd,ll *f,ll *res)
{
li r;
res[0]=0;
for(register int i=1;i<fd;i++)
{
r=0;
for(register int j=1;j<i;j++)
{
r+=(li)f[j]*res[i-j]%MOD;
}
res[i]=((li)i*f[i]%MOD-r%MOD+MOD)%MOD;
}
for(register int i=1;i<fd;i++)
{
res[i]=(li)res[i]*invl[i]%MOD;
}
}
inline void exp(ll fd,ll *f,ll *res)
{
li r;
res[0]=1;
for(register int i=1;i<fd;i++)
{
r=0,f[i]=(li)f[i]*i%MOD;
for(register int j=0;j<i;j++)
{
r+=(li)f[j+1]*res[i-j-1]%MOD;
}
res[i]=r%MOD*invl[i]%MOD;
}
}
int main()
{
n=read(),kk=read(),c=read(),invl[0]=invl[1]=finv[0]=finv[1]=fct=1;
for(register int i=2;i<65536;i++)
{
invl[i]=(MOD-(li)(MOD/i)*invl[MOD%i]%MOD)%MOD;
finv[i]=(li)finv[i-1]*invl[i]%MOD;
}
for(register int i=1;i<=n;i++)
{
xorv^=(x[i]=read());
for(register int j=0;j<=kk;j++)
{
v[i].pb(x[i]^(x[i]-j));
}
mp[v[i]]++;
}
for(auto i:mp)
{
v[++tot]=i.first,sm[tot]=i.second;
}
for(register int i=2;i<=kk;i++)
{
fct=(li)fct*i%MOD;
}
for(register int s=0;s<(1<<c);s++)
{
for(register int i=1;i<=tot;i++)
{
d=0;
for(register int j=0;j<=kk;j++)
{
d|=((popc(s&v[i][j])&1)<<j);
}
!cnt[d]?st[++tp]=d:1,cnt[d]+=sm[i];
}
memset(tmp,0,sizeof(tmp)),tmp[0]=1;
for(register int i=1;i<=tp;i++)
{
for(register int j=0;j<=kk;j++)
{
tmp2[j]=(st[i]&(1<<j))?MOD-finv[j]:finv[j];
}
ln(kk+1,tmp2,tmp3);
for(register int j=0;j<=kk;j++)
{
tmp3[j]=(li)tmp3[j]*cnt[st[i]]%MOD;
}
exp(kk+1,tmp3,tmp2),memset(tmp4,0,sizeof(tmp4));
for(register int j=0;j<=kk;j++)
{
for(register int k=0;k<=kk-j;k++)
{
tmp4[j+k]+=(li)tmp2[j]*tmp[k];
}
}
for(register int j=0;j<=kk;j++)
{
tmp[j]=tmp4[j]%MOD;
}
cnt[st[i]]=0;
}
tp=0,f[s]=(li)tmp[kk]*fct%MOD;
}
for(register int i=1;i<(1<<c);i<<=1)
{
for(register int p=0;p<(1<<c);p+=i<<1)
{
for(register int j=p;j<p+i;j++)
{
d=f[j],f[j]=(f[j]+f[j+i])%MOD,f[j+i]=(d-f[j+i]+MOD)%MOD;
}
}
}
d=(li)qpow(1<<c,MOD-2)*qpow(n,MOD-1-kk)%MOD;
for(register int i=0;i<(1<<c);i++)
{
printf("%d ",(li)f[i^xorv]*d%MOD);
}
}

CodeForces 1408I Bitwise Magic的更多相关文章

  1. Codeforces 1408I - Bitwise Magic(找性质+集合幂级数)

    Codeforces 题面传送门 & 洛谷题面传送门 Yet another immortal D1+D2 I %%%%%% 首先直接统计肯定是非常不容易的,不过注意到这个 \(k\) 非常小 ...

  2. Codeforces 424 C. Magic Formulas

    xor是满足交换律的,展开后发现仅仅要能高速求出 [1mod1....1modn],....,[nmod1...nmodn]的矩阵的xor即可了....然后找个规律 C. Magic Formulas ...

  3. codeforces 922 B. Magic Forest(枚举、位运算(异或))

    题目链接:点击打开链接 Imp is in a magic forest, where xorangles grow (wut?) A xorangle of order n is such a no ...

  4. 【Codeforces 1110E】Magic Stones

    Codeforces 1110 E 题意:给定两个数组,从第一个数组开始,每次可以挑选一个数,把它变化成左右两数之和减去原来的数,问是否可以将第一个数组转化成第二个. 思路: 结论:两个数组可以互相转 ...

  5. codeforces 710C C. Magic Odd Square(构造)

    题目链接: C. Magic Odd Square Find an n × n matrix with different numbers from 1 to n2, so the sum in ea ...

  6. CodeForces 628 D Magic Numbers 数位DP

    Magic Numbers 题意: 题意比较难读:首先对于一个串来说, 如果他是d-串, 那么他的第偶数个字符都是是d,第奇数个字符都不是d. 然后求[L, R]里面的多少个数是d-串,且是m的倍数. ...

  7. CodeForces 779E Bitwise Formula

    位运算,枚举. 按按分开计算,枚举$?$是$0$还是$1$,分别计算出$sum$,然后就可以知道该位需要填$1$还是$0$了. #include<map> #include<set& ...

  8. 【Codeforces 1117C】Magic Ship

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 我们可以把这个行船的过程分解成两个过程 1.船经过时间t被风吹到了某个地方 2.船用这t时间尝试到达终点(x2,y2) 会发现如果时间t能最终 ...

  9. CodeForces 778B - Bitwise Formula

    题意: 选择一个 m 位的二进制数字,总分为 n 个算式的答案之和.问得到最低分和最高分分别应该取哪个二进制数字 分析: 因为所有数字都是m位的,高位的权重大于低位 ,我们就从高到低考虑 ans 的每 ...

随机推荐

  1. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

  2. NIO 实现简单群聊功能

    服务端: package com.yang.runnable; import java.io.IOException; import java.net.InetSocketAddress; impor ...

  3. spring bean的init 方法和 destory方法的三种实现方式

    1.通过@Bean(initMethod ="initPerson",destroyMethod ="destroyPerson" ) public class ...

  4. Solon详解(九)- 渲染控制之定制统一的接口输出

    Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...

  5. python 系统设置

    1. 设置python运行环境为utf-8 import sys #引用sys模块 reload(sys) #重新加载sys sys.setdefaultencoding("utf-8&qu ...

  6. .NET Standard 版本支持

    系列目录     [已更新最新开发文章,点击查看详细] .NET标准已版本化.每个新版本都添加了更多的api.当库是针对某个.NET标准版本构建的时,它可以在实现该版本的.NET标准(或更高版本)的任 ...

  7. sql注入里关键字绕过的发现

    网上大量文章,甚至<黑客攻防技术实战宝典-WEB实战篇>里面都说一些关键字如 select 等绕过可以用注释符/**/. 例如: select,union.可以用 ,se/**/lect, ...

  8. Python实现好友生日提醒

    Python实现好友生日提醒  

  9. Git 看这一篇就够了

    上一篇讲 Git 的文章发出来没想到效果特别好,很多读者都要求继续深入的写. 那今天齐姐简单讲下 Git 的实现原理,知其所以然才能知其然:并且梳理了日常最常用的 12 个命令,分为三大类分享给你. ...

  10. markdown的基本使用

    1.什么是markdown? markdown是一种轻量级的标记语言 可以转换为html/xhtml和其它格式 可读.直观.学习成本低 当你学会使用markdown编写文档时,你会感觉自己发现了一个新 ...