(hdu 2089 不要62)

傳送門


Solution

  • 顯然暴力是會出滑稽的
  • f[i][j] 表示共有i位,其中最高位爲j的數的個數
  • 狀態轉移:
    f[i,j]代表開頭是j的i位數中不含”62”或”4”的數有幾個。
    如f[2,6]包含60,61,63,65,66,67,68,69
    f[0,0]=1;
    for(i=1 7)
    for(j=0 9)//i
    for(k=0 9)//i1
    ifj<>4||(j=6andk=2)continue;
    f[i,j]=f[i1,k]+f[i,j];

  • 關於統計答案:
    先預處理出數字x每一位的數字是幾,d[1]保存個位,d[2]保存十位,依次類推
    注意f數組的含義是有i位的數字的數的個數,而不是前i位的所有情況
    因此從高位開始枚舉每i位中比d[i]小的數,加入答案
    當第i位出現4或者與更高的位上的數字組成62的情況時,停止統計

  • 最後的答案是solve(m+1)-solve(n),

Code

// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;

int n,m;
LL f[7][10];
int d[10];

LL solve(int p){
    LL ret=0;
    int k=0;
    while(p){
        d[++k]=p%10;
        p/=10;
    }
    d[k+1]=0;
    for(int i=k;i>=1;--i){
        for(int j=d[i]-1;j>=0;--j)
            if(d[i+1]!=6||j!=2) 
                ret+=f[i][j];
        if(d[i]==4||(d[i+1]==6&&d[i]==2)) break;
    }
    return ret;
}

int main(){
    for(int i=0;i<=9;++i)
        if(i!=4) f[1][i]=1;
    for(int i=2;i<=7;++i)   
        for(int j=0;j<=9;++j)
            if(j!=4)
                for(int k=0;k<=9;++k){
                    if(k==2&&j==6) continue;
                    f[i][j]+=f[i-1][k];
                }
    while(scanf("%d%d",&n,&m)&&(n+m)){
        printf("%lld\n",solve(m+1)-solve(n));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章