第一个按位DP

whu出的题目,自己看着解题报告第一次懂了按位DP

HDU 3555
   
     
1 #include < iostream >
2 #include < cstdio >
3 #include < cstring >
4 #include < algorithm >
5   using namespace std;
6   /*
7 * 状态表示:
8 * 0 不含49且以非4的数字结尾
9 * 1 不含49且以4这个数字结尾
10 * 2 含49的状态
11 */
12 const int N = 33 ;
13 const int M = 10 ;
14 long long dp[N][M];
15 int digit[N];
16 int next( int now, int bit)
17 {
18 if (now == 0 )
19 {
20 if (bit == 4 ) return 1 ;
21 return 0 ;
22 }
23 else if (now == 1 )
24 {
25 if (bit == 9 ) return 2 ;
26 if (bit == 4 ) return 1 ;
27 return 0 ;
28 }
29 else return 2 ;
30 }
31
32 int main()
33 {
34 long long n;
35 int cases, len;
36 scanf( " %d " , & cases);
37 while (cases -- )
38 {
39 scanf( " %I64d " , & n);
40 n ++ ;
41 memset(digit, 0 , sizeof (digit));
42 long long tmp = n;
43 len = 0 ;
44 while (tmp != 0 )
45 {
46 digit[ ++ len] = tmp % 10 ;
47 tmp /= 10 ;
48 }
49 int now = 0 , b = 0 ;
50 long long ans = 0 ;
51 for ( int i = len;i > 0 ;i -- )
52 {
53 b ++ ;
54 for ( int j = 0 ;j < digit[i];j ++ )
55 {
56 memset(dp, 0 , sizeof (dp));
57 dp[b][next(now, j)] = 1 ;
58 for ( int k = b + 1 ;k <= len;k ++ )
59 {
60 dp[k][ 0 ] = dp[k - 1 ][ 1 ] * 8 + dp[k - 1 ][ 0 ] * 9 ;
61 dp[k][ 1 ] = dp[k - 1 ][ 0 ] + dp[k - 1 ][ 1 ];
62 dp[k][ 2 ] = dp[k - 1 ][ 2 ] * 10 + dp[k - 1 ][ 1 ];
63 }
64 ans += dp[len][ 2 ];
65 }
66 now = next(now, digit[i]);
67 }
68 printf( " %I64d\n " , ans);
69 }
70 return 0 ;
71 }

还不理解的就是按位DP和自动机的关系(自动机又白学了……)

我对题意的理解就是先确定某个前缀,然后依次向后推其数量

按位的转移方程位

dp[k][0] = dp[k - 1][1] * 8 + dp[k - 1][0] * 9;
dp[k][1] = dp[k - 1][0]  + dp[k - 1][1];
dp[k][2] = dp[k - 1][2] * 10 + dp[k - 1][1];

/*
 * 状态表示:
 * 0 不含49且以非4的数字结尾
 * 1 不含49且以4这个数字结尾
 * 2 含49的状态
 */
例如说12345

对其加1

求以

0位前缀长度位5的含49的数字的个数

然后是 以10 11为前缀的

以120 121 122 为前缀的

…………

最后是以

12345为前缀的

该前缀下该状态的初值为1,然后用上面的转移方程转移求解

本周计算方法考的极其纠结目前只能坐等悲剧……刚刚写完数据库实验报告。要写计组作业。

本周的任务是继续补习上周的按位DP内容(上周由于复习等原因导致只肤浅的学习了博弈的SG游戏)。

衡阳八中1026 windy数

衡阳1026
   
     
1 #include < iostream >
2 #include < vector >
3 #include < algorithm >
4 #include < numeric >
5 #include < cstring >
6 #include < cstdio >
7 #define DEBUG(x) cout << #x << " " << x << endl;
8 using namespace std;
9 const int LEN = 11 ;
10 int abs( int x)
11 {
12 return x < 0 ? - x : x;
13 }
14 int digit[LEN], dp[LEN][ 10 ];
15 void DP()
16 {
17 memset(dp, 0 , sizeof (dp));
18 for ( int i = 0 ; i < 10 ; i ++ )
19 dp[ 1 ][i] = 1 ;
20 for ( int i = 2 ; i < LEN; i ++ )
21 for ( int j = 0 ; j < 10 ; j ++ )
22 for ( int k = 0 ; k < 10 ; k ++ )
23 if (abs(j - k) >= 2 )
24 dp[i][j] += dp[i - 1 ][k];
25 }
26 int count( int n) // below n
27 {
28 int len = 0 ,tmp = n;
29 while (tmp)
30 {
31 digit[ ++ len] = tmp % 10 ;
32 tmp /= 10 ;
33 }
34 if (len == 1 ) return n - 1 ;
35 int ans = 0 ;
36 for ( int i = 1 ; i < len; i ++ )
37 ans += accumulate(dp[i] + 1 , dp[i] + 10 , 0 );
38 for ( int i = len; i > 1 ; i -- )
39 {
40 int j = i == len ? 1 : 0 ;
41 for (; j < digit[i]; j ++ )
42 {
43 if (i == len || abs(digit[i + 1 ] - j) >= 2 )
44 for ( int k = 0 ; k < 10 ; k ++ )
45 if (abs(j - k) >= 2 ) ans += dp[i - 1 ][k];
46 }
47 if (i < len && abs(digit[i + 1 ] - digit[i]) < 2 )
48 return ans;
49 }
50 for ( int i = 0 ;i < digit[ 1 ];i ++ )
51 ans += abs(digit[ 2 ] - i) >= 2 ;
52 return ans;
53 }
54 int main()
55 {
56 int a, b;
57 DP();
58 while (scanf( " %d %d " , & a, & b) == 2 )
59 printf( " %d\n " ,count(b + 1 ) - count(a));
60 return 0 ;
61 }


SGU一题 题号忘记了- -b 都是一个类型的思想

成都regional A题以及HDU3565 目前还不会

你可能感兴趣的:(dp)