#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;
}

 

posted @ 2020-02-15 21:10  xjqxjq  阅读(238)  评论(0编辑  收藏  举报