专栏文章
题解:P12236 [蓝桥杯 2023 国 Java A] 连续数组
P12236题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioitaqs
- 此快照首次捕获于
- 2025/12/02 19:54 3 个月前
- 此快照最后确认于
- 2025/12/02 19:54 3 个月前
此题注意到数据范围 ,且最后的问题是有多少种满足条件的连续数组,于是容易想到状压 DP。
解题过程
首先我们想该如何设计状态呢?首先第一维 想表示的是用到了哪些数,所以用 的二进制来表示这些状态。那么会不会有第二维呢?因为题目中还规定了两个相邻的数组元素的关系,所以还要有第二维 表示的是以 为结尾。于是就确定了状态: 表示在 的二进制下用到了一些数,并以 为结尾,这样子有多少种满足条件的连续数组。
确定状态是较难的一步,接下来就还好了。如何初始化?显然初始化只用一个数的情况,十分容易。
接下来就到了状态转移,我们先枚举 和 ,注意 在先前是要用到的,再枚举一个数 为 后面相邻的数(需要注意 在先前没有用到),当 满足相邻元素的关系时,就可以进行状态转移,令加入 后的状态压缩成二进制后变成了 ,就可以进行状态转移:
最后答案就是把所有数字结尾的情况相加即可。
代码
CPP#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 15;
int n;
ll dp[1 << N][N + 5];
bool pd[N + 5];
int js(int x){//计算x的二进制下有多少个1
int ct = 0;
while(x){
if(x & 1) ct++;
x >>= 1;
}
return ct;
}
int main(){
cin >> n;
for(int i = 1;i < n;i++) cin >> pd[i];
//初始化
for(int i = 0;i < n;i++) dp[1 << i][i] = 1;
int z = 1 << n;
for(int i = 1;i < z;i++){//第一层循环i
for(int j = 0;j < n;j++){//第二层循环j
if(!(i & (1 << j))) continue;//j一定是用到的,不满足条件就到不了下一层循环
int wz = js(i);//这是为了算一共用了几个数
for(int k = 0;k < n;k++){//枚举k
//条件1:k在先前没有出现
//条件2:满足这两个元素之间的关系
if(!(i & (1 << k)) && (pd[wz] == 1 && k == j + 1 || pd[wz] == 0 && k != j + 1)){
dp[i | (1 << k)][k] += dp[i][j];//状态转移
}
}
}
}
ll ans = 0;
//统计答案
for(int i = 0;i < n;i++) ans += dp[z - 1][i];
cout << ans;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...