正题

题目链接:https://www.luogu.com.cn/problem/CF838C


题目大意

一个字符串sss,两个人轮流操作,每次每个人可以选择删掉一个字符或者重排列这个字符串,但是不能出现之前出现过的字符串,不能操作者输。

求有多少个长度为nnn且字符集大小为kkk的字符串使得先手必胜。

1≤n≤250000,1≤k≤261\leq n\leq 250000,1\leq k\leq 261≤n≤250000,1≤k≤26


解题思路

显然如果删掉一个字符能使得先手必败,那么先手必胜。如果不能,那么肯定会一直重排列这个字符串。

那么如果一个字符串的排列数是偶数,那么先手可以切换先后手,所以先手必胜。否则先手需要考虑能否删除一个字符使得先手必败。

设第iii个字符的数量是aia_iai​,那么一个字符串可重排列的方案就是n!∏i=1kai!\frac{n!}{\prod_{i=1}^ka_i!}∏i=1k​ai​!n!​,并且如果删除一个字符iii,那么排列方式将会乘上ain\frac{a_i}{n}nai​​。

那么如果nnn是奇数,肯定存在一个aia_iai​是奇数,也就是说删除一个iii后排列方式的奇偶性不变。所以如果一个nnn是奇数且字符串的排列数是奇数,那么肯定可以删除一个字符使得排列数仍然是偶数。
那么如果nnn是奇数且先手,那么肯定不会被逼到一个走动后先手必胜的位置,所以nnn是奇数先手必胜。

然后如果nnn是偶数,那么如果排列方式是偶数那么先手必胜否则先手必败。

然后考虑怎么计数nnn是偶数的情况。考虑到一个n!n!n!包含的222质因数的个数为∑i=0⌊n2i⌋\sum_{i=0}\lfloor\frac{n}{2^i}\rfloor∑i=0​⌊2in​⌋,那么如果一个字符串的排列方式是偶数那么肯定有
∑i=0⌊n2i⌋=∑p=1k∑i=0⌊ap2i⌋\sum_{i=0}\left\lfloor\frac{n}{2^i}\right\rfloor=\sum_{p=1}^k\sum_{i=0}\left\lfloor\frac{a_p}{2^i}\right\rfloori=0∑​⌊2in​⌋=p=1∑k​i=0∑​⌊2iap​​⌋
然后又因为假设我们考虑一直分解xxx出来,显然∏i=1kai!\prod_{i=1}^ka_i!∏i=1k​ai​!的xxx肯定不会比n!n!n!中xxx多,同理分解2k2^k2k出来也是一样的,所以它们每一个iii求出来的答案都是恰好相等的,即
∀i∈N,⌊n2i⌋=∑p=1k⌊ap2i⌋\forall i\in N,\left\lfloor\frac{n}{2^i}\right\rfloor=\sum_{p=1}^k\left\lfloor\frac{a_p}{2^i}\right\rfloor∀i∈N,⌊2in​⌋=p=1∑k​⌊2iap​​⌋
那么aia_iai​求和的时候二进制就不能有进位了,也就是说对于nnn中的每个111,aia_iai​都恰好有一个是111,nnn中的每一个000,aia_iai​这一位都是000。

也就是把nnn的二进制分成若干份aia_iai​,每一份的贡献是1ai!\frac{1}{a_i!}ai​!1​,要求贡献的乘积和。这个分出一个部分来的转移其实就是子集卷积,所以我们跑kkk次子集卷积即可。

这样跑有点慢,所以我们还需要快速幂优化。

时间复杂度:O(klog⁡knlog⁡2n)O(k\log kn\log ^2n)O(klogknlog2n)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1<<19;
int n,k,P,f[20][N],g[20][N],c[N],inv[N],fac[N];
void FWT(int *f,int n,int op){for(int p=2;p<=n;p<<=1)for(int k=0,len=p>>1;k<n;k+=p)for(int i=k;i<k+len;i++)(f[i+len]+=f[i]*op)%=P;return;
}
signed main()
{scanf("%d%d%d",&n,&k,&P);int ans=1;for(int i=1;i<=n;i++)ans=1ll*ans*k%P;fac[0]=inv[0]=inv[1]=1;for(int i=2;i<N;i++)inv[i]=P-1ll*inv[P%i]*(P/i)%P;for(int i=1;i<N;i++)fac[i]=1ll*fac[i-1]*i%P,inv[i]=1ll*inv[i-1]*inv[i]%P;if(n&1)return printf("%d\n",ans)&0;f[0][0]=1;int m=1,lg=0;while(m<=n)m<<=1,lg++;for(int i=1;i<m;i++)c[i]=c[i-lowbit(i)]+1;for(int i=0;i<=n;i++)g[c[i]][i]=inv[i];for(int i=0;i<c[n];i++)FWT(g[i],m,1);FWT(f[0],m,1);while(k){if(k&1){for(int i=c[n];i>=0;i--){for(int x=0;x<m;x++)f[i][x]=1ll*f[i][x]*g[0][x]%P;for(int j=1;j<=i;j++)for(int x=0;x<m;x++)f[i][x]=(f[i][x]+1ll*f[i-j][x]*g[j][x])%P;}}for(int i=c[n];i>=0;i--){for(int x=0;x<m;x++)g[i][x]=(i?2ll:1ll)*g[0][x]*g[i][x]%P;for(int j=1;j<i;j++)for(int x=0;x<m;x++)g[i][x]=(g[i][x]+1ll*g[j][x]*g[i-j][x])%P;}k>>=1;}FWT(f[c[n]],m,-1);ans=(ans-1ll*f[c[n]][n]*fac[n]%P)%P;printf("%d\n",(ans+P)%P);return 0;
}

CF838C-Future Failure【dp,子集卷积】相关推荐

  1. CF914G Sum the Fibonacci(FWT模板+子集卷积)

    title 题目 solution (sa∣sb)&sc&(sd⊕se)=2i,i∈Z;sa&sb=0(s_a|s_b)\&s_c\&(s_d⊕s_e)=2^i ...

  2. 【学习笔记】FWT,子集卷积

    文章目录 1.概述 2.思想 3.按位或卷积 3.1.定义 3.2.正变换 3.3.逆变换 3.4.代码实现 4.按位与卷积 4.1.定义 4.2.正变换 4.3.逆变换 4.4.代码实现 5.按位异 ...

  3. 洛谷P6097:【模板】子集卷积(FWT)

    解析 完全可以当一道 DP 题而不是模板来做. 首先第一个条件: i∣j=ki|j=ki∣j=k 比较简单,直接上FWT板子即可. 考虑第二个条件:i&j=0i\&j=0i&j ...

  4. 背包DP | 子集和问题

    DP 成绩 10 开启时间 2020年03月10日 星期二 07:55 折扣 0.8 折扣时间 2020年04月7日 星期二 23:55 允许迟交 否 关闭时间 2020年04月7日 星期二 23:5 ...

  5. P6097-[模板]子集卷积

    正题 题目链接:https://www.luogu.com.cn/problem/P6097 题目大意 长度为2n2^n2n的序列a,ba,ba,b求一个ccc满足 ck=∑i∣j=k,i&j ...

  6. UVA 11825 状态压缩DP+子集思想

    很明显的状态压缩思想了.把全集分组,枚举每个集合的子集,看一个子集是否能覆盖所有的点,若能,则f[s]=max(f[s],f[s^s0]+1).即与差集+1比较. 这种枚举集合的思想还是第一次遇到,果 ...

  7. 快速沃尔什变换(FWT)及K进制异或卷积快速子集变换(FST)讲解

    前言: $FWT$是用来处理位运算(异或.与.或)卷积的一种变换.位运算卷积是什么?形如$f[i]=\sum\limits_{j\oplus k==i}^{ }g[j]*h[k]$的卷积形式(其中$\ ...

  8. Codeforces 1326F Wise Men (容斥原理、状压 DP、子集和变换、划分数)

    题目链接 F1: https://codeforces.com/contest/1326/problem/F1 F2: https://codeforces.com/contest/1326/prob ...

  9. Codeforces 1326F Wise Men (容斥原理、状压 DP、划分数)

    题目链接 F1: https://codeforces.com/contest/1326/problem/F1 F2: https://codeforces.com/contest/1326/prob ...

最新文章

  1. linux 常用命令:
  2. 引才125人!博士副处级待遇,硕士正科级,全部事业编​!限这些高校……
  3. Beta 冲刺(4/7)
  4. GitHub 给安全行业的四大启示
  5. 【模型解读】从2D卷积到3D卷积,都有什么不一样
  6. ningbooj--1655--木块拼接(贪心)
  7. leetcode117. 填充每个节点的下一个右侧节点指针 II
  8. Excel 关于新建xls文件 新建sheet 合并sheet的VBA操作代码
  9. lnk2019 mysql_C++使用MySQL-Connector/C++连接MySQL出现LNK2019错误的解决方法
  10. python模块:网络协议和支持
  11. 管理感悟:主管加班,员工才会加班
  12. 用 Python 高效办公|一次写好100个word通知
  13. 转载:Rootkit总结
  14. 一叶落而知天下秋暨“今目标”反思
  15. Unity使用脚本模拟Button按下
  16. 淘宝闲鱼京东等电商api的简单调用
  17. 腾讯云服务器的简单使用
  18. paypal注册教程(PP注册教程)paypal使用方法
  19. cad重新加载php命令,cad无限缩小的命令是什么
  20. Javascript中JSON与String相与转换

热门文章

  1. vue实现搜索框记录搜索历史_2018-09-13 基于Vue的搜索栏功能实现(we-ui)
  2. ab st语言编程手册_西门子PLC编程SCL和LAD谁才是王者?一起讨论一下
  3. 京东面试官:呦,你对中间件 Mycat了解的还挺深~
  4. android webview js 失效,Android WebView注入JQuery、JS脚本及执行无效的问题解决
  5. python数据字符_python数据清洗系列之字符串处理详解
  6. linux系统刷分辨率,Linux下设置其分辨率及刷新率
  7. aes算法实现c语言_以C语言实现归并排序为例,谈谈五大常用算法之一的“分治法”...
  8. 背包(二维数组版和一维数组版)
  9. 7-1 银行家算法--安全性检查 (20 分)(思路+详解+知识分析)宝 你今天 AC了吗
  10. [MySQL基础]数据库存储数据的特点