SGU 390-Tickets(数位dp)

题意:有标号l-r的票,要给路人发,当给的票的编号的各数位的总和(可能一个人多张票)不小k时,才开始发给下一个人,求能发多少人。

分析:这个题挺难想的,参考了一下题解,dp[i][sum][left] 长度i 当前数位和sum  前一子树剩余的和  

 

#include <map>

#include <set>

#include <list>

#include <cmath>

#include <queue>

#include <stack>

#include <cstdio>

#include <vector>

#include <string>

#include <cctype>

#include <complex>

#include <cassert>

#include <utility>

#include <cstring>

#include <cstdlib>

#include <iostream>

#include <algorithm>

using namespace std;

typedef pair<int,int> PII;

typedef long long ll;

#define lson l,m,rt<<1

#define pi acos(-1.0)

#define rson m+1,r,rt<<11

#define All 1,N,1

#define read freopen("in.txt", "r", stdin)

const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;

const int INF= 0x7ffffff;

const int mod =  1000000007;

ll l,r;

int k,lbit[20],rbit[20],used[20][210][1010];

struct node{

    ll num,left;//num能发的人数、left前一子树剩余和

    node(ll num = 0, ll left = 0) : num(num), left(left) {}

    node operator += (node b)

    {

        num += b.num;

        left = b.left;

        return *this;

    }

}dp[20][210][1010];

node dfs(int i,int sum,int left,int le,int re){

    if(i==0){

        if(sum+left>=k)

        return node(1,0);

        return node(0,sum+left);

    }

    if(used[i][sum][left]&&!le&&!re)

        return dp[i][sum][left];

    int ll=le?lbit[i]:0;

    int rr=re?rbit[i]:9;

    node a(0,left);

    for(int v=ll;v<=rr;++v){

        a+=dfs(i-1,sum+v,a.left,le&&(v==ll),re&&(v==rr));

    }

    if(!le&&!re){

        dp[i][sum][left]=a;

        used[i][sum][left]=1;

    }

    return a;

}

void solve(){

    memset(used,0,sizeof(used));

    memset(dp,0,sizeof(dp));

    int len=0;

    while(r){

        rbit[++len]=r%10;

        r/=10;

        lbit[len]=l%10;

        l/=10;

    }

    node t=dfs(len,0,0,1,1);

    printf("%I64d\n",t.num);

}

int main()

{

    scanf("%I64d%I64d%d",&l,&r,&k);

        solve();

return 0;

}

 

你可能感兴趣的:(dp)