首页 > 代码库 > bzoj1026

bzoj1026

http://www.lydsy.com/JudgeOnline/problem.php?id=1026

数位dp。。。

首先我们先把没有限制的dp出来,然后分类讨论,如果最高位比这个数的最高位小或者比这个数短的方案先加上去,然后讨论最高位等于这个数的情况。

比如说54321,我们把<50000的东西全部弄好了。

然后枚举,从a[0]-1开始,我们把(50000,53999)的加上,然后把(54200,54299)的加上,然后把(54300,54319)的加上,注意我们传的参数,最后把(54320,54321)的加上。

因为dp[i]表示第i位,所以每次我们加上的是从第i位到第一位的方案,只要i位和上一位满足条件,就可以加。

总结:先统计宽松的,最后统计天际线附近的,不断逼近。。。

技术分享
#include<bits/stdc++.h>
using namespace std;
int A, B;
int a[20], dp[20][20];
int solve(int n)
{
    int ret = 0; a[0] = 0;
    while(n) a[++a[0]] = n % 10, n /= 10; 
    for(int i = 1; i < a[0]; ++i) 
        for(int j = 1; j <= 9; ++j) ret += dp[i][j];
    for(int i = 1; i < a[a[0]]; ++i) ret += dp[a[0]][i];
    for(int i = a[0] - 1; i; --i)
    {
        for(int j = 0; j < a[i]; ++j) if(abs(j - a[i + 1]) >= 2) ret += dp[i][j];
        if(abs(a[i] - a[i + 1]) < 2) break;    
    }
    return ret;
}
int main()
{
    for(int i = 0; i <= 9; ++i) dp[1][i] = 1;
    for(int i = 2; i <= 10; ++i)
        for(int j = 0; j <= 9; ++j)
            for(int k = 0; k <= 9; ++k) if(abs(j - k) >= 2) dp[i][j] += dp[i - 1][k];        
    scanf("%d%d", &A, &B);
    printf("%d\n", solve(B + 1) - solve(A));
    return 0;
}
View Code

 

bzoj1026