CF327E Axis Walking
一、题目大意
给你一个长度为()的正整数序列,再有()个正整数。
求有多少种的排列方式使得其任意前缀和不会成为那个数里的任意一个。 答案对取模。
二、题目解析
这题很明了,一看就是状压
对于那些前缀和我们可以累加取得
不妨设表示当状态为时的前缀和
那么显然有中为的位置的
对于那些为给定的数的状态显然要舍去
那么不妨再设为状态为时的方案数
类似于的转移,显然有中为的位置的
发现这两者都需要访问那些状态中的的位置
那么对于这些状态中那些为的位置如何访问呢?
我们当然不能每次都让然后再判断这一位是否为,因为这样太慢了
所以我们需要快速地访问那些的位置
这时需要用到神奇(毒瘤)的位运算了
我们发现当时恰好能达到这一点
它相当于把最低位以后的部分全部消去了,相当于加速了我们的查找过程
于是乎,这题就与普通的状压无异了
三、完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7; //取模
const int N = 1 << 24; //最多24个数字
int n; //实际n个数字
int k; //k个不允许出现的数字
int full; //将所有位置全部为1时的拉满状态,对应的十进制数
unordered_set<int> no_permit; //有哪些数字是不允许出现在前缀和中的
int f[N]; //f[i]表示状态为i时的方案数
LL sum[N]; //sum[i]表示当状态为i时的前缀和
//一般状态压缩DP,n<=12,这里的n<=24,看来暴力的状态压缩要挂~
int lowbit(int x) {
return x & (-x);
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> sum[1 << i]; //按二进制位置映射的十进制数来存储(状态压缩式的存储方法)
//前缀和不允许出现的数字
cin >> k;
int x;
for (int i = 0; i < k; i++)cin >> x, no_permit.insert(x);
//状态为0时,表示一个全部都不选择,那么前缀和是0,肯定不在给定的k个正整数之中。因为正整数都大于0,这是一种唯一方案。
f[0] = 1, full = (1 << n) - 1;//满状态
//枚举现在的状态
for (int i = 1; i <= full; i++) {
//每次新的状态(sum[i]) = 仅有末尾1的状态 + 去掉末尾1的状态,而二者都在先前求过了,可以O(1)的求出sum[i] 的值
sum[i] = sum[i & ~lowbit(i)] + sum[lowbit(i)];
//sum[i] += sum[i - 1]; 这种传统方法是不可以的,因为sum数组并不是按一个个数字按次序保存的,而是按二进制数位方式保存的
//这所以这样保存,是因为状态压缩DP,是需要枚举每一个数位,每个数位与传统方式的前缀和不符,需要特殊记忆一下这个方法
//如果前缀和等于限定的数,那么是不合法的
if (no_permit.count(sum[i]))continue;
//快速找到所有位置为1的
for (int j = i; j; j -= lowbit(j))//枚举可能的上一次状态
f[i] = (f[i] + f[i & ~lowbit(j)]) % MOD; //去掉j位为1的 i & ~lowbit(j)
}
printf("%d\n", f[full]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-02-10 大数据统计分析平台之三、Kibana安装和使用
2018-02-10 大数据统计分析平台之一、Kafka单机搭建
2012-02-10 在Linux下配置squid[转载,待测试]
2012-02-10 内网用ssh连接linux很慢
2012-02-10 centos5.5 64位提升sata硬盘速度
2012-02-10 CentOS 64bit密码正确却无法登录系统
2012-02-10 Linux的内存释放脚本