安吉D10-T4
708 字
4 分钟
安吉D10-T4
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4本文
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
我们可以尝试使用 dp 来解决子序列问题.
定义 dp[i] 表示以第 个数结尾能够有多少满足要求的子序列.由于题意要求所有组合数的乘积模 2 大于 0,那就是要求所有组合数都是奇数.
转移方程为:
可以使用递推公式快速算出组合数.
这样能够拿到 40 pts.当 到二十万的数据规模就无法处理了,那该怎么办呢?
Lucas 定理:
当 时,
将 拆解,可得:
像这样拆解,最终可得:
其中, 分别表示 中二进制表示的第 位.
当且仅当 时,,故 等价于 ,即位运算中 . 其实就是 是 二进制中的子集.
因此,在 dp 时,尝试子集枚举.具体来说,遍历到 时,先将 增加 1,表示 单独成一组.再枚举 的所有子集 ,若 在后面出现过(设其处于 ),则说明 可以转移到 ,将 贡献给 .
子集枚举可以使用下面的代码:
for (int j = (a[i] - 1) & a[i]; j > 0; j = (j - 1) & a[i])请注意:由于题目中所要求的序列长度大于等于 2,因此最终答案需要减去 个长度为 1 的序列.
标程
#include <bits/stdc++.h>using namespace std;#define int long longconst 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;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


