bzoj 1026

很久以前做过的一道数位DP,现在用一种新的解决数位DP的比较一般的方法。

数位DP裸题是:求[L,R]有多少个数。

先转化成求[0,R]有多少个数,然后区间相减即可。

对于[0,R]中的所有数,用0补齐前面的空位,使得每个数的长度都为R的长度。

状态:

dp[pos][0]表示从最高位到pos位,没有顶上界的数的个数

dp[pos][1]表示从最高位到pos位,顶到上界的数的个数(好吧,这个问题中,它一定为1)

然后考虑转移,

dp[pos][0]->dp[pos-1][0](通过枚举pos-1位的数进行转移)

dp[pos][1]->dp[pos-1][0](通过枚举pos-1位,小于该位上界的数进行转移)

dp[pos][1]->dp[pos-1][1](只能在pos-1位填1)

顺推倒推都可以。

dp[1][0]+dp[1][1]就是答案。

对于其它的数位DP,都可以在这个DP上加上需要的状态维,然后解决其它问题。

上面的dp[pos][1]看似没有用(因为始终为1),但是实际上,我们是必须要它的,比如这道题。

我们设dp[pos][top][tail]表示:“比pos高的位,顶上界(top为1)或不顶上界(top为0),最后一位为tail的数的个数(并且要求这个数不为0)“

然后自己YY转移吧(这个不为0的要求和上一道题有点不同,具体看代码)。

新方法:

 1 /**************************************************************
 2     Problem: 1026
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:0 ms
 7     Memory:808 kb
 8 ****************************************************************/
 9
10 #include <cstdio>
11 #include <cstring>
12 #define abs(a) ((a)>0?(a):-(a))
13
14 typedef long long poi;
15
16 poi lf, rg;
17 int aa[20], tot;
18 poi dp[20][2][10];
19
20 poi calc( poi v ) {         //  v in [1,oo)
21     for( tot=0; v; v/=10 )
22         aa[++tot]=v%10;
23     memset( dp, 0, sizeof(dp) );
24     dp[tot][1][aa[tot]] = 1;
25     for( int i=1; i<aa[tot]; i++ )
26         dp[tot][0][i] = 1;
27     for( int i=tot; i>=2; i-- ) {
28         for( int c=0; c<=9; c++ )
29             for( int s=0; s<=9; s++ )
30                 if( abs(s-c)>=2 )
31                     dp[i-1][0][s] += dp[i][0][c];
32         for( int s=1; s<=9; s++ )
33             dp[i-1][0][s]++;
34         for( int s=0; s<aa[i-1]; s++ )
35             if( abs(s-aa[i])>=2 )
36                 dp[i-1][0][s] += dp[i][1][aa[i]];
37         dp[i-1][1][aa[i-1]] = dp[i][1][aa[i]] && abs(aa[i]-aa[i-1])>=2;
38     }
39     poi rt=dp[1][1][aa[1]];
40     for( int i=0; i<=9; i++ )
41         rt += dp[1][0][i];
42     return rt;
43 }
44 int main() {
45     scanf( "%lld%lld", &lf, &rg );
46     printf( "%lld\n", calc(rg)-(lf==1?0:calc(lf-1)) );
47 }

以前的:

 1 /**************************************************************
 2     Problem: 1026
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:0 ms
 7     Memory:804 kb
 8 ****************************************************************/
 9
10 #include <cstdio>
11 #include <algorithm>
12 using namespace std;
13
14 struct Form {
15     int n;
16     int b[30];
17     int src;
18     Form( int a ) {
19         n = 0;
20         src = a;
21         if( a==0 ) {
22             n=1;
23             b[1] = 0;
24             return;
25         }
26         while( a ) {
27             b[++n] = a%10;
28             a/=10;
29         }
30     }
31 };
32 int dp[10][11];     // dp[0~9][0~10]
33
34 void init() {
35     for( int h=0; h<=9; h++ )
36         dp[h][1] = 1;
37     for( int l=2; l<=10; l++ )
38         for( int h=0; h<=9; h++ )
39             for( int g=0; g<=9; g++ )
40                 if( abs(g-h)>=2 )
41                     dp[h][l] += dp[g][l-1];
42 }
43
44 int calc( const Form &fm) { //  [0,fm.src)
45     int ans = fm.src!=0;    //  0
46     for( int l=1; l<fm.n; l++ )
47         for( int h=1; h<=9; h++ ) {
48             ans += dp[h][l];
49             //printf( "(h=%d,l=%d)\n", h, l );
50         }
51     for( int h=1; h<fm.b[fm.n]; h++ ) {
52         ans += dp[h][fm.n];
53         //printf( "(h=%d,l=%d)\n", h, fm.n );
54     }
55     for( int l=fm.n-1; l>=1; l-- ) {
56         for( int h=0; h<fm.b[l]; h++ )
57             if( abs(h-fm.b[l+1])>=2 ) {
58                 ans += dp[h][l];
59                 //printf( "(h=%d,l=%d)\n", h, l );
60             }
61         if( abs(fm.b[l]-fm.b[l+1])<2 ) break;
62     }
63     return ans;
64 }
65
66 int main() {
67 //  freopen( "windy.in", "r", stdin );
68 //  freopen( "windy.out", "w", stdout );
69     int A, B, ans;
70     init();
71     scanf( "%d%d", &A, &B );
72     ans = calc(Form(B+1))-calc(Form(A));
73     printf( "%d\n", ans );
74 }

  

时间: 2024-12-07 11:21:01

bzoj 1026的相关文章

[bzoj 1026]windy数(数位DP)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总个数 那么f[i][j]=singma(f[i-1][k])(|j-k|>=2) 那么对于1~x(假设x从高到低的每位依次是x[n],x[n-1],……x[1])中的windy数个数就是f[n][0]+f[n][1]+……f[n][x[n]-1] + f[n-1][0]+f[n-1][1]+……f[

[BZOJ 1026] [SCOI 2009] Windy数 【数位DP】

题目链接:BZOJ - 1026 题目分析 这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题.. 对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a-1] 的答案.这样就化繁为简了. 具体过程见代码中的注释. 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath>

bzoj 1026 [SCOI2009]windy数(数位DP)

1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4550  Solved: 2039[Submit][Status][Discuss] Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数. Sample

[BZOJ 1026][SCOI 2009]windy数(数位DP)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1026 很基础的数位DP题,很早之前我就尝试做这题,不过当时我被这题吓死了,现在回过头做这题,感觉简单多了. 做这个题时我想到了POJ一道类似的组合数学的题,同样是按数位统计,有异曲同工之妙. 题目要求[a,b]区间上的windy数个数,我们可以转化成求[1,a]上的windy数个数-[1,b-1]上的windy数个数.题目转化成了求[1,x]上的windy数个数,我们就写个函数c

BZOJ 1026 windy数

Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数. Sample Input [输入样例一] 1 10 [输入样例二] 25 50 Sample Output [输出样例一] 9 [输出样例二] 20 HINT [数据规模和约定] 100%的数据,满足 1 <= A <= B <= 2

bzoj 1026 [SCOI2009]windy数 数位dp

1026: [SCOI2009]windy数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1026 Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数.

bzoj 1026 windy数(数位DP)

1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2615  Solved: 1155 [Submit][Status] Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数. Sample Input [

bzoj 1026 [ SCOI2009 ] windy数 —— 数位DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 蛮简单的数位DP,预处理 f[i][j] 表示 i 位数,以 j 开头的 windy 数个数: 但不明白为什么最后一位拿出来特判 ret++  不对,而写在循环里,特判 i==1 就对了... 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm&g

bzoj 1026 [SCOI2009]windy数——数位dp水题

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 迷恋上用dfs写数位dp了. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=15; int l,r,dg[N],dp[N][N]; int dfs(int p,int lst,bo