CF1605F PalindORme 解题报告
0.前置芝士
二项式反演:
f ( n ) = ∑ 0 ≤ i ≤ n ( n i ) g ( i ) ⟹ g ( n ) = ∑ 0 ≤ i ≤ n ( − 1 ) n − i ( n i ) f ( i ) 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)} f(n)=0≤i≤n∑(in)g(i)⟹g(n)=0≤i≤n∑(−1)n−i(in)f(i)
证明可参考这位大佬
1.题意简述
定义合法序列为重排后可满足:对于任意相同长度的前缀和后缀,它们的按位或和相等的序列。询问长度为n,值域为 [ 0 , 2 k − 1 ] [0,2^k-1] [0,2k−1] 的合法序列序列的个数。
(注意:我这里的合法序列序列和题中的 PalindORme 序列的定义不同)
2.判定
在解决对合法序列的计数之前,我们至少要先掌握它的判定。
根据定义,我们首先可以发现, a 1 = a n a_1 = a_n a1=an
进一步,
a
2
∣
(
a
1
)
=
a
n
−
1
∣
(
a
n
)
a
3
∣
(
a
1
∣
a
2
)
=
a
n
−
2
∣
(
a
n
∣
a
n
−
1
)
a
4
∣
(
a
1
∣
a
2
∣
a
3
)
=
a
n
−
3
∣
(
a
n
∣
a
n
−
1
∣
a
n
−
2
)
⋯
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
a2∣(a1)=an−1∣(an)a3∣(a1∣a2)=an−2∣(an∣an−1)a4∣(a1∣a2∣a3)=an−3∣(an∣an−1∣an−2)⋯
于是我们发现了一个判定合法序列的算法:
记前缀 or 值为 v a l val val。
如果能从序列中找到两个数 x x x, y y y, 使得 x ∣ v a l = y ∣ v a l x \mid val = y \mid val x∣val=y∣val,就令 v a l = v a l ∣ x val = val \mid x val=val∣x,并删去 x x x, y y y。
如果最后序列中剩下的数不超过1个,说明这个序列是合法序列,否则这个序列就是非法序列。
3.非法序列
我们发现,在经过了上述算法之后,非法序列所剩余的序列一定满足:删去 v a l val val所含有的二进制位后序列中的任意数互不相同且不为0。
我们把序列内任意数互不相同且不为0的序列称为 artalter 序列,那么任何一个非法序列都由一个合法序列和一个删去 v a l val val所含有的二进制位后为 artalter 序列的序列构成。
也就是说,我们在合法序列和非法序列之间建立了联系,这道题就有了突破口。
4.求解
说了这么多,我们终于进入正题了。
定义 A n , m A_{n,m} An,m为元素个数为 n n n,有 m m m 个二进制位的序列个数
定义 B n , m B_{n,m} Bn,m为元素个数为 n n n,有 m m m 个二进制位的 artalter 序列个数
定义 C n , m C_{n,m} Cn,m为元素个数为 n n n,有 m m m 个二进制位的不合法序列个数
根据乘法原理我们知道元素个数为 n n n,二进制位数小于等于 m m m 的序列个数为 ( 2 m ) n (2^{m})^{n} (2m)n
根据简单的组合知识,
(
2
m
)
n
=
∑
0
≤
i
≤
m
(
m
i
)
A
n
,
i
⟹
A
n
,
m
=
∑
0
≤
i
≤
m
(
−
1
)
m
−
i
(
m
i
)
(
2
i
)
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}}
(2m)n=0≤i≤m∑(im)An,i⟹An,m=0≤i≤m∑(−1)m−i(im)(2i)n
我们还知道元素个数为
n
n
n,二进制位数小于等于
m
m
m 的 artalter 序列个数为
(
2
m
−
1
)
n
‾
(2^{m}-1)^{\underline{n}}
(2m−1)n
(因为代表排列的
A
A
A 已被占用,所以这里使用了下降幂)
( 2 m − 1 ) n ‾ = ∑ 0 ≤ i ≤ m ( m i ) B n , i ⟹ B n , m = ∑ 0 ≤ i ≤ m ( − 1 ) m − i ( m i ) ( 2 i − 1 ) n ‾ (2^{m}-1)^{\underline{n}}=\sum_{0 \le i \le m}{\dbinom{m}{i}B_{n,i}}\\ \Longrightarrow B_{n,m}=\sum_{0 \le i \le m}{(-1)^{m-i}\dbinom{m}{i}(2^{i}-1)^{\underline{n}}} (2m−1)n=0≤i≤m∑(im)Bn,i⟹Bn,m=0≤i≤m∑(−1)m−i(im)(2i−1)n
最后,我们求出 C C C
C
n
,
m
=
∑
0
≤
i
<
n
∑
0
≤
j
<
m
(
n
i
)
(
m
j
)
(
A
i
,
j
−
C
i
,
j
)
(
2
j
)
n
−
i
B
n
−
i
,
m
−
j
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}}
Cn,m=0≤i<n∑0≤j<m∑(in)(jm)(Ai,j−Ci,j)(2j)n−iBn−i,m−j
这个式子的组合意义是:枚举有n个元素,有
m
m
m 个二进制位的非法序列中,最大的有i个元素,有
j
j
j 个二进制位的合法序列。
( n i ) ( m j ) \dbinom{n}{i}\dbinom{m}{j} (in)(jm)代表从n个元素中选取i个元素,从m个二进制位中选取j个为为合法序列所含有的二进制位。
( A i , j − C i , j ) (A_{i,j}-C_{i,j}) (Ai,j−Ci,j) 表示符合要求的合法序列的个数
( 2 j ) n − i (2^j)^{n-i} (2j)n−i 表示在所余序列中val包含的二进制位可以任取。
B n − i , m − j B_{n-i,m-j} Bn−i,m−j 表示在所余序列中val包含的二进制位以外的二进制位构成一个artalter序列
A n s = ∑ 0 ≤ i ≤ m ( m i ) ( A n , i − C n , i ) Ans=\sum_{0 \le i \le m}\dbinom{m}{i}(A_{n,i}-C_{n,i}) Ans=0≤i≤m∑(im)(An,i−Cn,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;
}