专栏文章

题解:P12236 [蓝桥杯 2023 国 Java A] 连续数组

P12236题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mioxvq7i
此快照首次捕获于
2025/12/03 02:56
3 个月前
此快照最后确认于
2025/12/03 02:56
3 个月前
查看原文

Solution

这道题目有点难看出该如何设计状态。但是我们注意到题目中所说的 numsnums 中的元素取值范围为 1N1∼N,就发现我们的状态 ii 其实表示一个数字是否用过,然后还要另有一个状态 jj 表示最后一个用到的数字,那么这道题目就很简单了。另外枚举一个数字 kk,可得出状态转移方程,读者自证不难。
dpi,j=dpi,j+dpi2j,kdp_{i,j}=dp_{i,j}+dp_{i-2^j,k}
但这个方程并不是随便乱用的,还得符合题目要求。还得判断 jjkk 是有序还是无序,具体的可以看代码。
至于初始化,当然是以每个数字开头的情况赋值为 11,其他的为 00。答案的话,就是
i=0n1dp2n1,i\sum_{i=0}^{n-1}{dp_{2^n-1,i}}
将以不同数字结尾的每种情况统计起来即可。

AC code

CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,a[16],dp[1<<16][16];
int num(int x){//这个num是用于计算一个数字在二进制下有多少个 1
	int res=0;
	while(x){
		x-=x&(-x);
		res++;
	}
	return res;
}
signed main(){
	cin>>n;
	for(int i = 1;i<n;i++) cin>>a[i];
	for(int i = 0;i<n;i++) dp[1<<i][i]=1;
	for(int i = 1;i<1<<n;i++){
		for(int j = 0;j<n;j++){
			if(i&(1<<j)==0) continue;
			for(int k = 0;k<n;k++){
				if(j==k||i&(1<<k)==0) continue;
				if(a[num(i)-1]==0&&j==k+1) continue;
				if(a[num(i)-1]&&j!=k+1) continue;
				dp[i][j]+=dp[i^(1<<j)][k];
			}
		}
	}
	int ans=0;
	for(int i = 0;i<n;i++) ans+=dp[(1<<n)-1][i];
	cout<<ans;
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...