视频加载失败

安吉D10-T4

708 字
4 分钟
安吉D10-T4
原题呈现

题目描述#

输入一个长度为 nn 的数列 a1,a2,,ana_1, a_2, \cdots, a_n,问有多少个长度大于等于 22 的不上升的子序列满足:

i=2k(abi1abi)mod2>0\prod_{i=2}^{k} \binom{a_{b_{i-1}}}{a_{b_i}} \bmod 2 > 0

输出这个个数对 10000000071000000007 取模的结果.

输入格式#

第一行一个整数 nn

接下来 nn 行,每行一个整数,第 ii 行表示 aia_i

输出格式#

一行一个整数表示答案.

样例#

样例输入#

4
15
7
3
1

样例输出#

11

数据范围#

  • 10%10\% 的测试点:n9n \le 91ai131 \le a_i \le 13
  • 20%20\% 的测试点:n17n \le 171ai201 \le a_i \le 20
  • 40%40\% 的测试点:n1911n \le 19111ai40001 \le a_i \le 4000
  • 70%70\% 的测试点:n2017n \le 2017
  • 85%85\% 的测试点:n100084n \le 100084
  • 100%100\% 的测试点:1n2119851 \le n \le 2119851ai2333331 \le a_i \le 233333

所有的 aia_i 互不相同,即不存在 iji \neq j 满足 ai=aja_i = a_j

我们可以尝试使用 dp 来解决子序列问题.

定义 dp[i] 表示以第 ii 个数结尾能够有多少满足要求的子序列.由于题意要求所有组合数的乘积模 2 大于 0,那就是要求所有组合数都是奇数.

转移方程为:

dp[i]=1+jj<idp[j],(ji)mod2=1dp[i]=1+\sum_{j}^{j <i}dp[j],\binom{j}{i}\bmod 2=1

可以使用递推公式快速算出组合数.

这样能够拿到 40 pts.当 aia_i 到二十万的数据规模就无法处理了,那该怎么办呢?

Lucas 定理

(xy)modp=(x/py/p)(xmodpymodp)modp\binom{x}{y}\bmod p=\binom{\lfloor x/p\rfloor}{\lfloor y/p\rfloor}\binom{x\bmod p}{y\bmod p}\bmod p

p=2p=2 时,

(xy)mod2=(x/2y/2)(xmod2ymod2)modp\binom{x}{y}\bmod 2=\binom{\lfloor x/2\rfloor}{\lfloor y/2\rfloor}\binom{x\bmod 2}{y\bmod 2}\bmod p

(x/2y/2)\binom{\lfloor x/2\rfloor}{\lfloor y/2\rfloor} 拆解,可得:

(xy)mod2=(x/4y/4)(x/2mod2y/2mod2)(xmod2ymod2)modp\binom{x}{y}\bmod 2=\binom{\lfloor x/4\rfloor}{\lfloor y/4\rfloor}\binom{\lfloor x/2\rfloor\bmod 2}{\lfloor y/2\rfloor\bmod 2}\binom{x\bmod 2}{y\bmod 2}\bmod p

像这样拆解,最终可得:

(xy)mod2=(xiyi)\binom{x}{y}\bmod 2=\prod\binom{x_i}{y_i}

其中,xi,y1x_i,y_1 分别表示 x,yx,y 中二进制表示的第 ii 位.

当且仅当 xi=0,yi=1x_i=0,y_i=1 时,(xiyi)=0\binom{x_i}{y_i}=0,故 (xy)mod2=1\binom{x}{y}\bmod 2=1 等价于 i,xi=0yi=0\forall i,x_i=0\Rightarrow y_i=0,即位运算中 xy=yx\wedge y=y. 其实就是 xxyy 二进制中的子集.

因此,在 dp 时,尝试子集枚举.具体来说,遍历到 a[i]a[i] 时,先将 f[i]f[i] 增加 1,表示 a[i]a[i] 单独成一组.再枚举 a[i]a[i] 的所有子集 kk,若 kk 在后面出现过(设其处于 a[j]a[j]),则说明 f[i]f[i] 可以转移到 f[j]f[j],将 f[i]f[i] 贡献给 f[j]f[j]

子集枚举可以使用下面的代码:

for (int j = (a[i] - 1) & a[i]; j > 0; j = (j - 1) & a[i])

请注意:由于题目中所要求的序列长度大于等于 2,因此最终答案需要减去 nn 个长度为 1 的序列.

标程

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 240000;
const int MOD = 1e9 + 7;
int n, a[N], id[N], f[N], ans;
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
id[a[i]] = i;
}
for (int i = 1; i <= n; i++) {
(f[i] += 1) %= MOD;
(ans += f[i]) %= MOD;
for (int j = (a[i] - 1) & a[i]; j > 0; j = (j - 1) & a[i]) {
if (id[j] > i)
(f[id[j]] += f[i]) %= MOD;
}
}
cout << ans - n;
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉D10-T4
https://blog.jerrylab.top/posts/problem/anji2026/D10/T4/
作者
Jerry
发布于
2026-08-10
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0