题意:给你4个数0,1,2,3,用这四个数字组成n位的数,其中 0必须 在1前面,  2必须在三前面,问你n位数没有前导0的有多少个。

解题思路:

1) 状态压缩DP,dp[i][j] 表示 到了第i位  出来了那几个数,分别的状态为多少。 j(1-15),然后求出各自的DP系数就行了。

解题代码:

  1 // File Name: 有趣的数.cpp
  2 // Author: darkdream
  3 // Created Time: 2015年03月30日 星期一 16时46分03秒
  4 
  5 #include<vector>
  6 #include<list>
  7 #include<map>
  8 #include<set>
  9 #include<deque>
 10 #include<stack>
 11 #include<bitset>
 12 #include<algorithm>
 13 #include<functional>
 14 #include<numeric>
 15 #include<utility>
 16 #include<sstream>
 17 #include<iostream>
 18 #include<iomanip>
 19 #include<cstdio>
 20 #include<cmath>
 21 #include<cstdlib>
 22 #include<cstring>
 23 #include<ctime>
 24 #define LL long long
 25 #define M 1000000007
 26 using namespace std;
 27 LL dp[2000][17];
 28 int a[10];
 29 int b[10];
 30 int solve(int tmp , int t[])
 31 {
 32   int tt =0 ; 
 33   while(tmp)
 34   {
 35     tt ++ ; 
 36     t[tt] = tmp % 2; 
 37     tmp /= 2;
 38   }
 39 }
 40 int ok(int x , int y)
 41 {
 42    memset(a,0,sizeof(a));
 43    memset(b,0,sizeof(b));
 44    solve(x,a);
 45    solve(y,b);
 46    if(x == y )
 47    {
 48       int tt1 = a[1] + a[2];
 49       int tt2 = a[3] + a[4];
 50       int k = 0 ;
 51       if(tt1)
 52           k ++ ;
 53       if(tt2 )
 54           k ++ ; 
 55       return k ; 
 56    }
 57    int tx = 0 ; 
 58    int ty = 0 ; 
 59    for(int i = 1;i <= 4;i ++)
 60        tx += a[i];
 61    for(int i = 1;i <= 4;i ++)
 62        ty += b[i];
 63    int c = 0 ; 
 64    for(int i = 1;i <= 4;i ++)
 65        if(a[i] != b[i])
 66            c ++; 
 67    if(tx - ty  == 1 && c == 1 )
 68    {
 69        if(b[1] == 0 && a[1] == 1)
 70        {
 71            if(b[2] == 1)
 72                return 0 ; 
 73        }
 74        if(b[3]== 0 &&  a[3] == 1){
 75            if(b[4] == 1)
 76                return 0 ; 
 77        }
 78        return 1; 
 79    }else{
 80      return 0 ;
 81    }
 82 }
 83 int main(){
 84    int n ;
 85    scanf("%d",&n);
 86    dp[1][1] = 0 ; 
 87    dp[1][2] = 1 ;
 88    dp[1][4] = 1;
 89    dp[1][8] = 1; 
 90    for(int i = 2  ;i <= n;i ++)
 91    {
 92       for(int j= 1;j <= 15 ;j ++)
 93       {
 94          for(int s = 1; s <= 15;s ++)
 95          {
 96             if(ok(j,s) != 0 )
 97             {
 98               dp[i][j] = (dp[i][j]+ok(j,s)*dp[i-1][s])%M;
 99             }
100          }
101         // printf("%lld ",dp[i][j]);
102       }
103      // printf("\n");
104    }
105    
106    printf("%d\n",dp[n][15]%M);
107 return 0;
108 }
View Code

2) 组合数学。

具体参见:http://erona.me/2014/12/05/CCF%E6%A8%A1%E6%8B%9F%E9%A2%98-%E6%9C%89%E8%B6%A3%E7%9A%84%E6%95%B0/

posted on 2015-03-30 19:57  dark_dream  阅读(367)  评论(0编辑  收藏  举报