题目链接: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;
}