[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];这些保证区间首尾数的位数相等的子区间分别求然后加起来。

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

posted @ 2016-03-27 11:51  cx_oier  阅读(201)  评论(0编辑  收藏  举报