[SCOI2009]windy数

哎。。。我最讨厌数位DP。。写了这么长调完了。

主要是注意可以取得区间的处理问题以及边界。。挂了好久

代码长,写的丑,不要喷

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define lld long long
using namespace std;

lld mabs(lld x){
    if(x < 0){
        return -x;
    }
    return x;
}
lld a,b;
int getlen(lld x){
    int cnt = 0;
    while(x){
        cnt++;
        x /= 10;
    }
    return cnt;
}
void geti(lld x,lld len,int* haha){
    while(x){
        haha[len--] = x % 10;
        x /= 10;
    }
}
lld dp[20][10];
lld sdp[20][10];
int tmp1[20];
int tmp2[20];
void ini(){
    for(int i = 0;i<=9;i++){
        dp[1][i] = 1;
        sdp[1][i] = i+1;
    }
    for(int i = 2;i<=20;i++){
        for(int j = 0;j<=9;j++){
            if(j >= 2){
                dp[i][j] += sdp[i-1][j-2];
            }
            if(j <= 7){
                dp[i][j] += sdp[i-1][9] - sdp[i-1][j+1];
            }
        }
        sdp[i][0] = dp[i][0];
        for(int j = 1;j<=9;j++){
            sdp[i][j] = sdp[i][j-1] + dp[i][j];
        }
    }
}
int llen;
int slove1(int now,int type){
    if(now == llen+1){
        return 1;
    }
    if(type == 1){
            lld tmpans = 0;
            int ul = max(tmp1[now-1] +2,tmp1[now]);
            int dl = tmp1[now-1] -2;
            if(ul <= 9){
                tmpans += sdp[llen-now+1][9]-sdp[llen-now+1][ul-1];
            }
            if(ul == tmp1[now]){
                tmpans -= dp[llen-now+1][tmp1[now]];
            }
            if(dl >= tmp1[now]){
                tmpans += sdp[llen-now+1][dl]-(sdp[llen-now+1][tmp1[now]]);
            }
            if(tmp1[now] >= ul || tmp1[now] <= dl){
                tmpans += slove1(now+1,1);
            }
            return tmpans;
    }
    else if(type == 2){
        lld tmpans = 0;
            int ul = tmp2[now-1]+2;
            int dl = min(tmp2[now],tmp2[now-1] -2);
            if(ul <= tmp2[now]){
                tmpans += sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][ul-1];
            }
            if(dl >= 0){
                tmpans += sdp[llen-now+1][dl];
            }
            if(dl == tmp2[now]){
                tmpans -= dp[llen-now+1][tmp2[now]];
            }
            if(tmp2[now] >= ul || tmp2[now] <= dl){
                tmpans += slove1(now+1,2);
            }
            return tmpans;
    }
    else{
        if(tmp2[now] == tmp1[now]){
            if(now == 1 || mabs(tmp1[now-1]-tmp1[now]) >= 2){
                return slove1(now+1,0);
            }
            return 0;
        }
        else{
            lld tmpans = 0;
            if(now == 1){
                return sdp[llen-now+1][tmp2[now]-1] - sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2);
            }
            int ul = tmp1[now-1] +2;
            int dl = tmp2[now-1] -2;
            if(tmp2[now] >= ul){
                if(tmp1[now] >= ul){
                    return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2);
                }
                else{
                    return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][ul-1]+slove1(now+1,2);
                }
            }
            if(tmp1[now] <= dl){
                if(tmp2[now]<=dl){
                    return sdp[llen-now+1][tmp2[now]-1]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1)+slove1(now+1,2);
                }
                else{
                    return sdp[llen-now+1][dl]-sdp[llen-now+1][tmp1[now]]+slove1(now+1,1);
                }
            }
            return 0;
        }
    }
}
int slove(lld bgin,lld end,lld len){
    geti(bgin,len,tmp1);
    geti(end,len,tmp2);
    llen = len;
    return slove1(1,0);
}
lld anss = 0;
int main(){
    freopen("1.in","r",stdin);
    freopen("my.out","w",stdout);
    ini();
    scanf("%lld %lld",&a,&b);
    int len1 = getlen(a);
    int len2 = getlen(b);
    if(len1 != len2){
        anss += slove(a,pow(10,len1)-1,len1);
        len1++;
        while(len1 < len2){
            anss += slove(pow(10,len1-1),pow(10,len1)-1,len1);
            len1++;
        }
        anss += slove(pow(10,len1-1),b,len1);
    }
    else{
        anss = slove(a,b,len1);
    }
    printf("%lld\n",anss);
    return 0;
}

主要思路:裸的数位DP。。但是细节很多。。

dp[i][j]:长度为i的数字第一位是j(每一位均可取0-9,可以有前导0)的符合题意的数字个数。

sdp[i][j]:对每一个i的dp[i][j]的前缀和;在slove1会用到;

我把[a,b]的区间分成了[a,x1],[x1+1,x2],.....[xn,b];这些保证区间首尾数的位数相等的子区间分别求然后加起来。

一定考虑好区间的交并问题。。。

时间: 2024-08-07 20:15:47

[SCOI2009]windy数的相关文章

bzoj1026 [SCOI2009]windy数

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

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

bzoj1026: [SCOI2009]windy数(数位dp)

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

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 一个整数.

【数位DP】bzoj1026: [SCOI2009]windy数

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

1026: [SCOI2009]windy数(数位dp)

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

luogu P2657 [SCOI2009]windy数 数位dp 记忆化搜索

题目链接 luogu P2657 [SCOI2009]windy数 题解 我有了一种所有数位dp都能用记忆话搜索水的错觉 代码 #include<cstdio> #include<algorithm> inline int read() { int x = 0,f = 1; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c <= '9' && c >= '

【luogu2657】【bzoj1026】 [SCOI2009]windy数 [动态规划 数位dp]

P2657 [SCOI2009]windy数 bzoj1026 一本通说这是一道数位dp模板题 emmmmm 就是逐位确定 f[i][j]表示填了i位数其最高位数字为j 然后就去求可能方案数 分为 不满足x的位数的严格小于x的全部情况 和x的位数相同 但最高位小于x的最高为的全部方案数 和x的位数相同 有一位比x的对应位数小的全部方案数 其余位数对应数字都相同(这是数位dp常用的一个性质:对于一个小于n的数 它从高位到低位一定会出现某一位上的数字小于n所对应这一位上的数字) PS 因为x不一定为

bzoj1026: [SCOI2009]windy数 数位dp

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1026 题意: Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数 思路: 数位dp,记忆化搜索. 1 #include <bits/stdc++.h> 2 3 using namesp

bzoj 1026 SCOI2009 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