SGU 390 Tickets(数位DP)

来源:互联网 发布:ubuntu owncloud 编辑:程序博客网 时间:2024/04/30 06:05

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=390


题意:有一位售票员给乘客售票。对于每位乘客,他会卖出多张连续的票,直到已卖出的票的 编号的数位之和不小于给定的正数 k。然后他会按照相同的规则给下一位乘客售票。初始时, 售票员持有的票的编号是从 L 到 R 的连续整数。请你求出,售票员可以售票给多少位乘客。


思路:每次dfs时记录当前的数字之和sum及前一个子树剩余的数字rem,如果sum + rem大于k就把剩余数字清零


#include <cstdio>#include <cstring>#include <queue>#include <stack>#include <functional>#include <utility>#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <set>#include <cmath>#include <stdlib.h>#include <climits>#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1#pragma comment (linker, "/STACK:1024000000,1024000000")typedef long long ll;using namespace std;const int maxn = 20;const int maxk = 1010;struct node{    ll cnt, rem;    node(ll cnt = 0, ll rem = 0) : cnt(cnt), rem(rem) {}    node operator += (node nxt)    {        cnt += nxt.cnt;        rem = nxt.rem;        return *this;    }} dp[maxn][maxn * 10][maxk];bool vis[maxn][maxn * 10][maxk];int dl[maxn], dr[maxn];ll l, r, k;node dfs(int h, ll sum, ll rem, bool lim1, bool lim2){    if (h == 0)    {        if (sum + rem >= k)            return node(1, 0);        return node(0, sum + rem);    }    if (vis[h][sum][rem] && !lim1 && !lim2)        return dp[h][sum][rem];    node ans(0, rem);    int low = lim1 ? dl[h] : 0;    int upp = lim2 ? dr[h] : 9;    for (int i = low; i <= upp; i++)        ans += dfs(h - 1, sum + i, ans.rem, lim1 && i == low, lim2 && i == upp);    if (!lim1 && !lim2)    {        dp[h][sum][rem] = ans;        vis[h][sum][rem] = 1;    }    return ans;}int main(){    cin >> l >> r >> k;    int cnt = 1;    while (l)    {        dl[cnt++] = l % 10;        l /= 10;    }    cnt = 1;    while (r)    {        dr[cnt++] = r % 10;        r /= 10;    }    node ans = dfs(cnt, 0, 0, 1, 1);    cout << ans.cnt << endl;    return 0;}


0 0