Luogu P3773 [CTSC2017]吉夫特 题解
Description
输入一个长度为 n 的数列 a1,a2,…,an 问有多少个长度大于等于 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.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 如何做好软件架构师
· 欧阳的2024年终总结,迷茫,重生与失业
· 聊一聊 C#异步 任务延续的三种底层玩法
· 上位机能不能替代PLC呢?
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· .NET Core:架构、特性和优势详解