洛谷题面传送门

首先 \(3^n\) 的做法就不多说了,相信对于会状压 dp+会枚举子集的同学来说不算困难(暴论),因此这篇博客将着重讲解 \(2^nn^2\) 的做法。

首先如果我们把每个 \(a_i\) 看作一个集合幂级数 \(1+x^{a_i}\),那么我们的任务就是把所有这样的集合幂级数做一遍子集卷积对吧。直接做一脸过不去。不过注意到这个式子的形式比较特别,事实上学过多项式&生成函数的同学应该对形如 \(1+x^k\) 的式子特别敏感,因为在生成函数那套理论中有个恒等式 \(\ln(1+x^k)=\sum\limits_{i}(-1)^{i+1}\dfrac{x^{ik}}{i}\),因此考虑将这东西与多项式扯上关系。考虑子集卷积的本质:将所有 \(x^{S}\) 看作一个二维函数 \(x^{S}y^{|S|}\),然后对 \(x\) 的指数做 or 卷积,对 \(y\) 的指数做加法卷积。那么我们考虑做这样一件事:把所有集合幂级数 \(F(S)\) 写成 \(\sum\limits_{S}F_{S}(y)x^S\) 的形式,也就是外层是集合幂级数,内层是一个关于 \(y\) 的多项式。那么考虑两个幂级数 \(F(S)\) 和 \(G(S)\) 做子集卷积得到的幂级数 \(H(S)\),必然有 \(H_i(y)=\sum\limits_{j|k=i}F_j(y)G_k(y)\),因此在这种定义下,对两个幂级数进行子集卷积的过程即是:将 \(F_{S}(y)x^S\) 做一遍 FWTor,也就是把平时对整数的 FWTor 的加法改为多项式加法,对 \(G_S(y)x^S\) 也做一遍同样的操作,然后令 \(H_S(y)=F_S(y)G_S(y)\),也就是将 FWT 后对应位置上的多项式卷起来,然后再 IFWTor 回去即可。

直接照着上面的方式做还是会 TLE,不过注意到将集合幂级数 \(1+x^{a_i}\) 进行一遍 FWTor 后得到的集合幂级数比较特别,具体来说,\(1=x^0y^0\) 显然可以对 FWTor 后所有位置上的数产生贡献,因此所有位置上的 \(F_S(y)\) 都有一个 \(y^0\),而 \(x^{a_i}=x^{a_i}y^{|a_i|}\) 显然只能对 \(a_i\in S\) 的 \(S\) 产生贡献,因此对于所有 \(a_i\in S\) 的 \(S\) 有 \(F_S(y)=y^{|a_i|}+1\),其余 \(S\) 有 \(F_{S}(y)=1\)。

它 出 现 了!\(y^{a_i}+1\) 显然与前面 \(1+x^k\) 是同一形式的,因此它的 \(\ln\) 我们也是可以非常轻松求得的,而我们在 FWTor 之后,按照套路是要把对应位置上的多项式全部卷起来的,按照多项式的套路我们可以先取 \(\ln\) 再 \(\exp\) 回去,看,你要的 \(\ln(y^{a_i}+1)\) 不就来了吗?我们记 \(H(S)\) 为将所有集合幂级数卷起来后得到的集合幂级数,那么对于所有 \(S\),\(\ln(\text{FWT}(H_S(y)))\) 是很好求的,具体步骤是:我们先记 \(F_{i,S}(y)\) 为一个幂级数,满足对于 \(S=a_i\),\(F_{i,S}(y)=\ln(y^{|a_i|}+1)\),其余 \(F_{i,S}=0\),对这东西对应位置上的多项式求个和,然后跑遍高维前缀和(或者你爱叫它 FWTor 我也没意见)即可,求完 \(\ln(H_S(y))\) 以后 \(\exp\) 回去即可得到 \(\text{FWT}(H_S(y))\),然后再一波 IFWTor 即可得到真正的系数,由于多项式的长度最多只有 \(18\),因此 \(\exp\) 不用任意模数 NTT,直接暴力求即可。

const int MAXN=1<<18;
const int LOG_V=18;
const int MOD=1e9+7;
int pr[MAXN/6+5],prcnt=0,vis[MAXN+5],phi[MAXN+5];
void sieve(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]) pr[++prcnt]=i,phi[i]=i-1;
for(int j=1;j<=prcnt&&pr[j]*i<=n;j++){
vis[pr[j]*i]=1;
if(i%pr[j]==0){phi[i*pr[j]]=phi[i]*pr[j];break;}
phi[i*pr[j]]=phi[i]*phi[pr[j]];
}
}
}
int n,a[MAXN+5],f[MAXN+5][LOG_V+2],tmp[LOG_V+2],inv[LOG_V+2];
int main(){
scanf("%d",&n);sieve(MAXN);
for(int i=(inv[0]=inv[1]=1)+1;i<=LOG_V;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1,x;i<=n;i++) scanf("%d",&x),a[x]++;
for(int i=1;i<MAXN;i++){
int cnt=__builtin_popcount(i);
for(int j=1;j<=LOG_V/cnt;j++){
if(j&1) f[i][j*cnt]=(f[i][j*cnt]+1ll*inv[j]*a[i])%MOD;
else f[i][j*cnt]=(f[i][j*cnt]-1ll*inv[j]*a[i]%MOD+MOD)%MOD;
}
}
for(int i=2;i<=MAXN;i<<=1)
for(int j=0;j<MAXN;j+=i)
for(int k=0;k<(i>>1);k++)
for(int l=0;l<=LOG_V;l++){
f[(i>>1)+j+k][l]=(f[(i>>1)+j+k][l]+f[j+k][l])%MOD;
}
for(int i=0;i<MAXN;i++){
memset(tmp,0,sizeof(tmp));tmp[0]=1;
for(int j=1;j<=LOG_V;j++){
for(int k=0;k<j;k++)
tmp[j]=(tmp[j]+1ll*f[i][j-k]*(j-k)%MOD*tmp[k])%MOD;
tmp[j]=1ll*tmp[j]*inv[j]%MOD;
}
for(int j=0;j<=LOG_V;j++) f[i][j]=tmp[j];
}
for(int i=2;i<=MAXN;i<<=1)
for(int j=0;j<MAXN;j+=i)
for(int k=0;k<(i>>1);k++)
for(int l=0;l<=LOG_V;l++){
f[(i>>1)+j+k][l]=(f[(i>>1)+j+k][l]-f[j+k][l]+MOD)%MOD;
}
int ans=0;
for(int i=0;i<MAXN;i++) ans=(ans+1ll*phi[i+1]*f[i][__builtin_popcount(i)])%MOD;
for(int i=1;i<=a[0];i++) ans=2*ans%MOD;
printf("%d\n",ans);
return 0;
}

洛谷 P6570 - [NOI Online #3 提高组] 优秀子序列(集合幂级数+多项式)的更多相关文章

  1. luogu P6570 [NOI Online #3 提高组]优秀子序列 二进制 dp

    LINK:P6570 [NOI Online #3 提高组]优秀子序列 Online 2的T3 容易很多 不过出于某种原因(时间不太够 浪了 导致我连暴力的正解都没写. 容易想到 f[i][j]表示前 ...

  2. 洛谷 P6478 - [NOI Online #2 提高组] 游戏(二项式反演+树形 dp)

    题面传送门 没错这就是我 boom0 的那场 NOIOL 的 T3 一年前,我在 NOIOL #2 的赛场上折戟沉沙,一年后,我从倒下的地方爬起. 我成功了,我不再是从前那个我了 我们首先假设 A 拥 ...

  3. 洛谷P1003 铺地毯 noip2011提高组day1T1

    洛谷P1003 铺地毯 noip2011提高组day1T1 洛谷原题 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n ...

  4. 洛谷-神奇的幻方-NOIP2015提高组复赛

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  5. 洛谷 P1541 乌龟棋 & [NOIP2010提高组](dp)

    传送门 解题思路 一道裸的dp. 用dp[i][j][k][kk]表示用i个1步,j个2步,k个3步,kk个4步所获得的最大价值,然后状态转移方程就要分情况讨论了(详见代码) 然后就是一开始统计一下几 ...

  6. 洛谷 P1525 关押罪犯 & [NOIP2010提高组](贪心,种类并查集)

    传送门 解题思路 很显然,为了让最大值最小,肯定就是从大到小枚举,让他们分在两个监狱中,第一个不符合的就是答案. 怎样判断是否在一个监狱中呢? 很显然,就是用种类并查集. 种类并查集的讲解——团伙(很 ...

  7. 洛谷 P5019 铺设道路 & [NOIP2018提高组](贪心)

    题目链接 https://www.luogu.org/problem/P5019 解题思路 一道典型的贪心题. 假设从左往右填坑,如果第i个深与第i+1个,那么第i+1个就不需要额外填: 如果第i+1 ...

  8. 洛谷P1063 能量项链 [2006NOIP提高组]

    P1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标 记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子 ...

  9. 「洛谷P1080」「NOIP2012提高组」国王游戏 解题报告

    P1080 国王游戏 题目描述 恰逢 \(H\)国国庆,国王邀请\(n\)位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 \( ...

随机推荐

  1. javascript-jquery对象的其他处理

    一.对元素进行遍历操作 如果要遍历一个jquery对象,对其中每个匹配元素进行相应处理,那么可以使用each()方法. $("div").each(function(index,e ...

  2. 洛谷 P2252 [SHOI2002]取石子游戏|【模板】威佐夫博弈

    链接: P2252 [SHOI2002]取石子游戏|[模板]威佐夫博弈 前言: 第一眼大水题,第二眼努力思考,第 N 眼我是大水逼. 题意: 不看题目标题都应该能看出来是取石子类的博弈论. 有两堆石子 ...

  3. PCIE笔记--PCIe错误定义与分类

    转载地址:http://blog.chinaaet.com/justlxy/p/5100057782 前面的文章提到过,PCI总线中定义两个边带信号(PERR#和SERR#)来处理总线错误.其中PER ...

  4. DDR3 IP和CIC IP仿真问题解决记录

    1.更新vivado的仿真库(data/secureip和verilog和vhdl文件夹)至最新的vivado库和生成IP的版本匹配: 2.vcs编译脚本里面把仿真库地址指向匹配的仿真库版本: 3.v ...

  5. Shadertoy 教程 Part 4 - 绘制多个2D图形和混入

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

  6. 彻底解决SLF4J的日志冲突的问题

    今天公司同事上线时发现,有的机器打印了日志,而有的机器则一条日志也没有打.以往都是没有问题的. 因此猜测是这次开发间接引入新的日志jar包,日志冲突导致未打印. 排查代码发现,系统使用的是SLF4J框 ...

  7. 手撸markdown web server

    先上效果图 在线预览 powered by kingreatwill/mdserve. markdown项目:https://github.com/kingreatwill/open 目的 经常写笔记 ...

  8. CSP2020-儒略历

    大家可以在洛谷提交: 题目描述 为了简便计算,天文学家们使用儒略日(Julian day)来表达时间.所谓儒略日,其定义为从公元前 4713 年 1 月 1 日正午 12 点到此后某一时刻间所经过的天 ...

  9. Linux 兴趣小组2016免试题 第四关揭秘

    Linux 兴趣小组2016免试题 点这里 首先贴出第四关链接Linux 兴趣小组2016免试题 第四关 第四关: 进入网址我们看到的是4张扑克牌K,这是什么意思? 要我斗地主?好了,还是乖乖的先查看 ...

  10. vs Code配置C++运行和调试环境以及相关问题

    vs Code配置C++运行和调试环境以及相关问题 第一步:下载c++插件 第二步:安装编译.调试环境 如果没有Dev-C++下载MinGW 下载地址:https://sourceforge.net/ ...