CF1605F PalindORme 解题报告
作者:互联网
CF1605F PalindORme 解题报告
0.前置芝士
二项式反演:
\[f(n)=\sum_{0 \le i \le n}{\dbinom{n}{i}g(i)}\\ \Longrightarrow g(n)=\sum_{0 \le i \le n}{(-1)^{n-i}\dbinom{n}{i}f(i)} \]证明可参考这位大佬
1.题意简述
定义合法序列为重排后可满足:对于任意相同长度的前缀和后缀,它们的按位或和相等的序列。询问长度为n,值域为 \([0,2^k-1]\) 的合法序列序列的个数。
(注意:我这里的合法序列序列和题中的 PalindORme 序列的定义不同)
2.判定
在解决对合法序列的计数之前,我们至少要先掌握它的判定。
根据定义,我们首先可以发现,\(a_1 = a_n\)
进一步,
\[a_2\mid(a_1)=a_{n-1}\mid(a_n)\\ a_3\mid(a_1\mid a_2)=a_{n-2}\mid(a_n \mid a_{n-1})\\ a_4\mid(a_1\mid a_2 \mid a_3)=a_{n-3}\mid(a_n \mid a_{n-1} \mid a_{n-2})\\ \dotsb \]于是我们发现了一个判定合法序列的算法:
记前缀 or 值为 \(val\)。
如果能从序列中找到两个数 \(x\),\(y\), 使得 \(x \mid val = y \mid val\),就令 \(val = val \mid x\),并删去 \(x\),\(y\)。
如果最后序列中剩下的数不超过1个,说明这个序列是合法序列,否则这个序列就是非法序列。
3.非法序列
我们发现,在经过了上述算法之后,非法序列所剩余的序列一定满足:删去\(val\)所含有的二进制位后序列中的任意数互不相同且不为0。
我们把序列内任意数互不相同且不为0的序列称为 artalter 序列,那么任何一个非法序列都由一个合法序列和一个删去\(val\)所含有的二进制位后为 artalter 序列的序列构成。
也就是说,我们在合法序列和非法序列之间建立了联系,这道题就有了突破口。
4.求解
说了这么多,我们终于进入正题了。
定义 \(A_{n,m}\)为元素个数为 \(n\),有 \(m\) 个二进制位的序列个数
定义 \(B_{n,m}\)为元素个数为 \(n\),有 \(m\) 个二进制位的 artalter 序列个数
定义 \(C_{n,m}\)为元素个数为 \(n\),有 \(m\) 个二进制位的不合法序列个数
根据乘法原理我们知道元素个数为 \(n\),二进制位数小于等于 \(m\) 的序列个数为\((2^{m})^{n}\)
根据简单的组合知识,
\[(2^{m})^{n}=\sum_{0 \le i \le m}{\dbinom{m}{i}A_{n,i}}\\ \Longrightarrow A_{n,m}=\sum_{0 \le i \le m}{(-1)^{m-i}\dbinom{m}{i}(2^{i})^{n}} \]我们还知道元素个数为 \(n\),二进制位数小于等于 \(m\) 的 artalter 序列个数为 \((2^{m}-1)^{\underline{n}}\)
(因为代表排列的 \(A\) 已被占用,所以这里使用了下降幂)
最后,我们求出 \(C\)
\[C_{n,m}=\sum_{0 \le i < n}\sum_{0 \le j < m}{\dbinom{n}{i}\dbinom{m}{j}(A_{i,j}-C_{i,j})(2^j)^{n-i}B_{n-i,m-j}} \]这个式子的组合意义是:枚举有n个元素,有 \(m\) 个二进制位的非法序列中,最大的有i个元素,有 \(j\) 个二进制位的合法序列。
\(\dbinom{n}{i}\dbinom{m}{j}\)代表从n个元素中选取i个元素,从m个二进制位中选取j个为为合法序列所含有的二进制位。
\((A_{i,j}-C_{i,j})\) 表示符合要求的合法序列的个数
\((2^j)^{n-i}\) 表示在所余序列中val包含的二进制位可以任取。
\(B_{n-i,m-j}\) 表示在所余序列中val包含的二进制位以外的二进制位构成一个artalter序列
\[Ans=\sum_{0 \le i \le m}\dbinom{m}{i}(A_{n,i}-C_{n,i}) \]5.代码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL f[105][105];
int A[105][105], C[105][105], B[105][105];
LL fsp(LL a, LL b, LL mod)
{
LL s = 1;
while (b)
{
if (b & 1)
s = (s * a) % mod;
b >>= 1;
a = a * a % mod;
}
return s;
}
LL low(LL x,LL y,LL mod){
LL s=1;
for(int i=x;i>=x-y+1;i--)s*=i,s%=mod;
return s;
}
int main()
{
LL n, m, mod;
cin >> n >> m >> mod;
for (int i = 0; i <= 100; i++)
{
f[i][0] = f[i][i] = 1;
for (int j = 1; j < i; j++)
{
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % mod;
}
}
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
for(int k=0;k<=j;k++){
A[i][j]+=fsp(-1,j-k,mod)*f[j][k]%mod*fsp(2,k*i,mod)%mod;
B[i][j]+=fsp(-1,j-k,mod)*f[j][k]%mod*low(fsp(2,k,mod)-1,i,mod)%mod;
A[i][j]%=mod,B[i][j]%=mod;
}
}
}
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
for(int i_=0;i_<i;i_++){
for(int j_=0;j_<j;j_++){
if(n%2==1&&i==n&&i_==n-1){
continue;
}
C[i][j]+=f[i][i_]*f[j][j_]%mod*fsp(2,j_*(i-i_),mod)%mod*B[i-i_][j-j_]%mod*(A[i_][j_]-C[i_][j_]+mod)%mod;
C[i][j]%=mod;
}
}
}
}
LL ans=0;
for(int i=0;i<=m;i++){
ans+=f[m][i]*(A[n][i]-C[n][i])%mod;
}
cout<<(ans%mod+mod)%mod;
return 0;
}
标签:le,CF1605F,dbinom,二进制位,LL,mid,解题,序列,PalindORme 来源: https://www.cnblogs.com/artalter/p/16439265.html