HDU - 5787 K-wolf Number 數位DP

傳送門

水人今天多校打了一會就不行了,感覺自己都不會做。。。一直讓隊友單挑怪不好意思的,所以過了一會就跑掉了。。晚上回來補題發現有個數位DP,做了做,一開始因爲細節問題沒處理好wa了一發,改了之後過了。。。好感動。。原來我能做啊。。。= =

lim:當前數字上限是否有限制,無限制爲9,有限制爲給出的數字 pos:當前位置 kk:標記當前已經選了幾個數字,如果小於k個則爲0,否則爲1 mod:由於最大上限是5位,所以用一個模來存儲 c:當前是第幾位       pos是反的,c是正的。。恩 就這樣 然後只要二維就夠了,只存當前位置和那個模,然後注意細節,然後沒了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int maxn = 31;
long long l,r;
int k,m,len;
int s[maxn];
long long d[maxn][100005];
long long cal(int lim,int pos,int kk,int mod,int c){
    if(pos<0) return 1;
    if(!lim&&d[pos][mod]!=-1) return d[pos][mod];
    int up = 9;
    if(lim) up = s[pos];
    long long res = 0;
    for(int i=0;i<=up;i++){
        int tlim = 0,tmod = (mod*10);
        if(lim&&i == up) tlim = 1;
        if(pos == len-1) {
            res += cal(tlim,pos-1,kk||(c+1)>=k,(tmod+i)%m,min(c+1,k));
            continue;
        }
        int tt = tmod/10,flag = 1,tc = c;
        while(tt){
            tc --;
            if(tc == 0) break;
            if(i == tt%10) flag = 0;
            tt /= 10;
        }
        if(flag) res += cal(tlim,pos-1,kk||(c+1)>=k,(tmod+i)%m,min(c+1,k));
    }
    if(!lim) d[pos][mod] = res;
    return res;
}
int main(){
    while(~scanf("%lld%lld%d",&l,&r,&k)){
        memset(d,-1,sizeof d);
        l --;
        len = 0;
        m = 1;
        for(int i=0;i<k;i++)
            m *= 10;
        while(r){
            s[len++] = r%10;
            r /= 10;
        }
        long long t1 = cal(1,len-1,0,0,1);
        len = 0;
        while(l){
            s[len++] = l%10;
            l /= 10;
        }
        long long t2 = cal(1,len-1,0,0,1);
        printf("%lld\n",t1-t2);
    }
    return 0;
}



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