Luogu P3773 [CTSC2017]吉夫特 题解

Link

Description

输入一个长度为 \(n\) 的数列 \(a_1,a_2,\dots ,a_n\) 问有多少个长度大于等于 \(2\) 的不上升子序列满足:

\[\Pi _{i=2}^{k} \binom{a_{b_{i-1}}}{a_{b_i}} \mod 2 = \binom{a_{b_1}}{a_{b_2}} \times \binom{a_{b_2}}{a_{b_3}} \times \cdots \binom{a_{b_{k-1}}}{a_{b_k}} \mod 2 > 0 \]

Solution

根据 Lucas定理:当 \(p\) 为质数时,\(C_n^m \mod p \equiv C_{n\mod p}^{m \mod p} \times C_{n/p}^{m/p} \mod p\)

本题中 \(p\)\(2\),也就是对 \(n,m\) 的二进制的每一位进行考虑。

因为,\(C_1^1=1,C_1^0=1,C_0^0=1,C_0^1=0\)

所以只要在任意组合数的二进制中存在一位 \(n_i = 0\), \(m_i=1\),那么就是不合法的,即 \(n\&m=m\)

所以相当于取出来一个子序列,使得 \(a_{i-1} \& a_i = a_{i-1}\),即 \(a_{i-1}\subseteq a_i\)

\(f_i\) 表示以 \(a_i\) 开头的合法子序列的数量,用桶记录一下每个 \(a_i\) 出现的位置,对于 \(f_i\),枚举 \(a_i\) 的子集,判断位置是否在 \(i\) 后面,转移即可。

Code

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 3e5;
const int p = 1e9 + 7;
int n, a[N], id[N], f[N], ans;

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]), id[a[i]] = i;
    for(int i = n; i >= 1; i--)
        for(int j = a[i] & (a[i] - 1); j; j = a[i] & (j - 1))
            if(id[j] > i) f[i] = (f[i] + f[id[j]] + 1) % p;
    for(int i = 1; i <= n; i++)
        ans = (ans + f[i]) % p;
    printf("%d\n", ans);
    return 0;
}
posted @ 2021-10-08 21:53  Acestar  阅读(61)  评论(0编辑  收藏  举报