Luogu P3773 [CTSC2017]吉夫特 题解
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;
}
$$A\ drop\ of\ tear\ blurs\ memories\ of\ the\ past.$$