题意
对于输入的n,n<=30,求有多少个不超过n位2进制的数,有连续的3个1
分析
组合数学的做法看不懂,于是想到dp推一下
dp[i][j]表示到i位为止,末尾有j个1的方案数,由于完全不知道序列是什么,靠自己脑补,于是有两种
最后,我们只需要用总方案数减去安全的方案数,即到n位为止,末尾也没有三个1的情况
转移(注意,末尾已经有三个情况不是安全的方案数,所以j<3):
- dp[i][0]+=dp[i-1][j] (当前这位是0,前面无论有几个1,结尾也都是0)
- dp[i][j]+=dp[i-1][j-1] (当前这位是1,前面如果有j-1个1,现在就有j个1)
再形象一点解释,其实就是统计了11001101...1001001 这些乱七八糟所有的1总是被0隔开而未达到3个方案数总和。
代码
#include<bits/stdc++.h> using namespace std; #define N 40 int n,dp[N][N]; long long ans; inline void DP() { memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<=2;j++)dp[i][0]+=dp[i-1][j]; for(int j=1;j<=2;j++)dp[i][j]+=dp[i-1][j-1]; } ans=0; for(int i=0;i<=2;i++)ans+=dp[n][i]; printf("%lld ",(1<<n)-ans); } int main() { while(scanf("%d",&n)&&n)DP(); return 0; }