#3211. 吉夫特
题目描述
简单的题目,既是礼物,也是毒药。
B 君设计了一道简单的题目,准备作为 gift 送给大家。
输入一个长度为 $n$ 的数列 $a_1, a_2 , \dots, a_n$ 问有多少个长度大于等于 $2$ 的不上升的子序列 $a_{b_1}, a_{b_2}, \ldots, a_{b_k}$ 满足
$$ \prod\limits_{i = 2} ^ k \binom{a_{b_{i - 1}}}{a_{b_i}} \bmod 2 = \binom{a_{b_1}}{a_{b_2}} \times \binom{a_{b_2}}{a_{b_3}} \times \cdots \times \binom{a_{b_{k - 1}}}{a_{b_k}}\bmod 2 > 0 $$
输出这个个数对 $1000000007$ 取模的结果。
题解
考虑 $\text{Lucas}$ 定理, $(_m^n)=(_{m\%2}^{n\%2})(_{m/2}^{n/2})$,列举一下,发现只有 $(_1^0)=0$ ,说明要满足 $(_m^n)$ 是奇数那必须 $m \And n=m$,
所以我们可以考虑暴力: $f[i][s]$ 表示前 $i$ 个数, $s$ 值为末尾的方案数,然后暴力枚举即可,效率不是很优,发现 $s \le 2^18$ ,于是我们可以考虑把 $s$ 分前 $9$ 位和后 $9$ 位,即 $f[i][j][k]$ 表示前 $i$ 个数,最后的状态的前 $9$ 位为 $j$ ,后 $9$ 位的子集为 $k$ 的方案数的总和,这样效率就是 $O(2^9n)$ 了
代码
#include <bits/stdc++.h> using namespace std; const int P=1e9+7; int n,f[512][512],s; int main(){ cin>>n; for (int x,y,v,i=1;i<=n;i++){ scanf("%d",&x); y=x&511;x>>=9;v=f[x][y]; for (int j=x;j<512;j=(j+1)|x) (f[x][y]+=f[j][y])%=P; (f[x][y]+=1)%=P; v=(P-v+f[x][y])%P;(s+=(v+P-1)%P)%=P; for (int j=(y-1)&y;j;j=(j-1)&y) (f[x][j]+=v)%=P; if (y) (f[x][0]+=v)%=P; } cout<<s<<endl;return 0; }