发现只要式子中有一个数为奇数,整个式子就为 \(0\)

把膜数代到每一乘积项中,容易发现这个东西就是一个 \(\text{Lucas}\) 定理。

卢卡斯定理有一个性质,那就是如果膜数是 \(p\),那么使用 \(\text{Lucas}\) 定理就和 \(p\) 进制数类似。

递归展开 \(\text{Lucas}\) 就容易发现对于 \({n \choose m}\),如果出现 \(n = 0,m = 1\)\({ 0 \choose 1 }\) 的情况,那么这个式子就是 \(0\) 了。

根据 \(\text{Lucas}\) 定理 \(p\) 进制数的性质,直接位运算 \(n | m\) 即可判断一个组合数是否为奇数。

然后仿照最长上升子序列这样的问题写个 \(dp\) 转移就行了,转移就是枚举子集,因为转移条件是或运算,复杂度是 \(O(3^n)\) 证明大概就是二项式定理整整就出来了。

代码放一下,免得以后忘了枚举子集怎么写。

#include <cstdio>
#include <algorithm>
#include <cstring>

using std::max;

typedef long long ll;

const int MAXN = 211985 + 5;
const int MAXA = 233333 + 5;
const int MOD = 1e9 + 7;

int n, a[MAXN << 1];
int id[MAXA << 1];
ll f[MAXA << 1];

int main() {

    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        id[ a[i] ] = i;
    }
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int s = (a[i] - 1) & a[i]; s; s = (s - 1) & a[i]) {
            if (id[s] > i) {
                f[s] = (f[s] + f[ a[i] ] + 1) % MOD;
            }
        }
        ans = (ans + f[ a[i] ]) % MOD;
    }
    printf("%lld\n", ans);

    return 0;
}

复杂度证明:

 posted on 2022-11-27 09:57  Louis_660  阅读(37)  评论(0编辑  收藏  举报