扫雷 洛谷p2327

来源:互联网 发布:多玩数据库5.4 编辑:程序博客网 时间:2024/06/16 14:35

题目描述

输入输出格式

输入格式:

第一行为N,第二行有N个数,依次为第二列的格子中的数。(1<= N <= 10000)

输出格式:

一个数,即第一列中雷的摆放方案数。

输入输出样例

输入样例#1: 复制
21  1
输出样例#1: 复制
2

如果从上到下确定每个雷的位置,那么判断某个位置能否为雷只受它上面2格雷的情况影响,于是可以将i-2~i的雷记录为一个3位的二进制数。考虑状压dp,dp[i][sta]表示前i个雷,i-2~i的雷的分布为sta时的总数,那么dp[i][sta]=dp[i-1][(sta>>1)|4]+dp[i-1][sta>>1],表示第i-2的位置放不放雷。转移前需要判断sta这个状态是否合法。设counter(x)为x的二进制表示中1的个数,num为第二列对应的数字,合法也就意味着counter(sta)==num[i-1]且counter(sta>>1)<=num[i],此时就可以进行转移。

#include<iostream>#include<cstdio>#define f(i,l,r) for(i=(l);i<=(r);i++)using namespace std;const int MAXN=10005;int n,a[MAXN];int dp[MAXN][8],f[8];inline int cal(int x){int i,num=0;for(i=x;i;i-=(i&(-i))){num++;}return num;}inline void MakeTable(){int i;f(i,0,7) f[i]=cal(i);}int main(){//ios::sync_with_stdio(false);//freopen("data.out","r",stdin);//freopen("test.out","w",stdout);int i,j,ans=0;MakeTable();cin>>n;f(i,1,n)  cin>>a[i];dp[1][1]=dp[1][0]=1;f(i,2,n-1){f(j,0,7){if(f[j]!=a[i-1]||f[j&3]>a[i]) continue;dp[i][j]=dp[i-1][(j>>1)|4]+dp[i-1][j>>1];//cout<<i<<' '<<j<<' '<<dp[i-1][(j>>1)|4]<<' '<<dp[i-1][j>>1]<<"GG"<<endl;}}f(i,0,7){if(f[i]!=a[n-1]||f[i&3]!=a[n])  continue;ans+=dp[n-1][(i>>1)|4]+dp[n-1][i>>1];}cout<<ans<<endl;return 0;}


原创粉丝点击