DP - 數位DP - SCOI 2009 - Windy數 + HDU 2089 - 不要62

DP - 數位DP - SCOI 2009 - Windy數 + HDU 2089 - 不要62


1、SCOI 2009 - Windy數

Windy 定義了一種 Windy 數:不含前導零且相鄰兩個數字之差至少爲 2 的正整數被稱爲 Windy 數。

Windy 想知道,在 A 和 B 之間,包括 A 和 B,總共有多少個 Windy 數?

輸入格式
共一行,包含兩個整數 A 和 B。

輸出格式
輸出一個整數,表示答案。

數據範圍
1≤A≤B≤2×109

輸入樣例1:
1 10
輸出樣例1:
9
輸入樣例2:
25 50
輸出樣例2:
20

——《數字遊戲f類似,僅僅在f數組轉移條件上有些不同。

N首先將N每一位取出存入數組,

從高位到低位依次枚舉每一位,

N=V=Vn1Vn2...V0last=f[i][j]ijjk>=2f[i][j]+=f[i1][k]j,k[0,9]設N=V=V_{n-1}V_{n-2}...V_0,last=前一位數的大小,\\f[i][j]表示長度爲i且最高位是j的合法方案總數。\\則在|j-k|>=2的情況下,f[i][j]+=f[i-1][k],j,k∈[0,9]。

ij考慮第i位數j,
j<Vijlast>=2iVres+=f[i+1][j]①、若j<V_i且|j-last|>=2,無論後i位取何值,均不會大於V,故方案總數res+=f[i+1][j]。

Vilast<2退last=Vi②、若|V_i-last|<2,則之後無論如何也不會枚舉出合法方案,直接退出循環,否則更新last=V_i。

a0V③、當枚舉到最後一位a_0時,再加上V本身這一合法方案。

注意:

ij1考慮到最高位的前導零問題,當i在最高位時,j從1開始枚舉。

[1,n1]最後要單獨加上所有含前導零的方案,長度從[1,n-1]。

代碼:

#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=11;

int f[N][N];

void cal()
{
    for(int i=0;i<=9;i++) f[1][i]=1;
    
    for(int i=2;i<N;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                if(abs(j-k)>=2) 
                    f[i][j]+=f[i-1][k];
}

int dp(int n)
{
    if(!n) return 0;
    
    vector<int> V;
    while(n) V.push_back(n%10),n/=10;
    
    int res=0,last=-2;
    for(int i=V.size()-1;i>=0;i--)
    {
        int x=V[i];
        for(int j=(i==V.size()-1);j<x;j++)
            if(abs(j-last)>=2)
                res+=f[i+1][j];
                
        if(abs(x-last)>=2) last=x;
        else break;
        
        if(!i) res++;
    }
    
    for(int i=1;i<V.size();i++)
        for(int j=1;j<=9;j++)
            res+=f[i][j];

    return res;
}

int main()
{
    cal();
    
    int l,r;
    cin>>l>>r;
    cout<<dp(r)-dp(l-1)<<endl;
    
    return 0;
}

2、HDU 2089 - 不要62

杭州人稱那些傻乎乎粘嗒嗒的人爲 62(音:laoer)。

杭州交通管理局經常會擴充一些的士車牌照,新近出來一個好消息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大衆。

不吉利的數字爲所有含有 4 或 62 的號碼。例如:62315,73418,88914 都屬於不吉利號碼。但是,61152 雖然含有 6 和 2,但不是 連號,所以不屬於不吉利數字之列。

你的任務是,對於每次給出的一個牌照號區間 [n,m],推斷出交管局今後又要實際上給多少輛新的士車上牌照了。

輸入格式
輸入包含多組測試數據,每組數據佔一行。

每組數據包含一個整數對 n 和 m。

當輸入一行爲“0 0”時,表示輸入結束。

輸出格式
對於每個整數對,輸出一個不含有不吉利數字的統計個數,該數值佔一行位置。

數據範圍
1≤n≤m≤109

輸入樣例:
1 100
0 0
輸出樣例:
80

分析:

與第一題思路完全一致,僅僅修改轉移條件。

代碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N=11;

int f[N][N];

void cal()
{
    for(int i=0;i<=9;i++)
        if(i!=4)
            f[1][i]=1;
    
    for(int i=2;i<N;i++)
        for(int j=0;j<=9;j++)
        {
            if(j==4) continue;
            for(int k=0;k<=9;k++)
            {
                if(k==4 || j==6&&k==2)  continue;
                f[i][j]+=f[i-1][k];
            }
        }
}

int dp(int n)
{
    if(!n) return 1;
    
    vector<int> V;
    while(n) V.push_back(n%10),n/=10;
    
    int res=0,last=0;
    for(int i=V.size()-1;i>=0;i--)
    {
        int x=V[i];
        for(int j=0;j<x;j++)
        {
            if(j==4 || last==6&&j==2) continue;
            res+=f[i+1][j];
        }
        
        if(x==4 || last==6&&x==2) break;
        last=x;
        
        if(!i) res++;
    }
    
    return res;
}

int main()
{
    cal();
    int l,r;
    while(cin>>l>>r,l||r)
        cout<<dp(r)-dp(l-1)<<endl;
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章