定義數的消除操作爲選定[L,R,x],如果數的第L到第R位上的數字都大於等於x,並且這些數都相等,那麼該操作是合法的(從低位到高位編號,個位是第一位,百位是第二位……),然後將這些位數上的數減x;否則就是不合法的,不能進行操作。對一個數操作最少的次數使得這個數變成0,這個操作次數稱爲該數的最小操作數。如:1232的最小操作數爲3,一個合法解是[2,2,1],[1,3,2],[4,4,1]。
求L~R中最小操作數爲k的數的個數。
例如:132,需要操作3次才能變爲0。而131131 => 111131 => 111111 =>0
單組測試數據。 三個整數L、R和k(1<=L<=R<=10^18,1<=k<=18)。
一個整數表示答案。
10 21 2
9
明顯的數位dp,但是做的時候不知道如何求1到x裏面符合要求的個數有多少個。
下面是官方題解:(表示維護一個棧的思路簡直了,又被自己低智商給感動了)
對於一個數計算最小操作數:
維護一個棧。
從高位到低位依次考慮每一位,設當前數字爲x,將棧裏所有大於x的數字刪除,如果此時棧裏沒有數字x則加入,並且答案+1。
用一個二進制數來表示棧裏有哪些元素。
因爲可以按位考慮所以可以用數位dp來做這個問題。
最後答案等於1~R裏符合要求的數量-1~L-1裏符合要求的數量。所以這裏只考慮1~R的計算。
設數字R有n位,a[i]表示第i位。(從低位到高位編號,個位是第一位,百位是第二位……)
設某數第i位的數字爲x,且x<a[i],且第i+1位~第n位數字與R相同,將這個數記爲(i,x),
可以通過這個標準將數分類,最多18*9種分類。
對於一種分類,統計這種分類裏有幾個數符合題目要求。
計算出此時棧的狀態和已累加的答案(即最小操作數),記爲 t1,t2 , dp[t1][i−1][K−t2] 爲這類裏符合要求的數的數量(K爲輸入要求的最小操作數)。
dp[i][j][k] 表示當前棧裏的元素狀態爲i,再填j位數字,使答案(即最小操作數)剛好再加k的方案數,這個可以通過枚舉下一位數字轉移得到。
總複雜度O(18*512*18*10)
代碼:
//#pragma comment(linker, "/STACK:102400000,102400000")
#pragma warning(disable:4996)
#include <fstream>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <ctime>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define eps 1e-10
#define LL_INF 0x3fffffffffffffff
#define INF 0x3f3f3f3f
#define mem(a, b) memset(a, b, sizeof(a))
#define pper(i,n,m) for(int i = n;i >= m; i--)
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back
const int maxn = 8005;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
ll L, R, k;
ll res[20][20][1050];
int dig[20];
int change(int s, int x)
{
int i, j, k;
for (i = 0; i <= 9; i++)
{
if ((i > x) && (s >> i & 1))
{
s ^= (1 << i);
}
}
return s | (1 << x);
}
ll dfs(int len, int num, int sta,int up)
{
if (len == 0)
{
return num == k;
}
if (!up&&res[len][num][sta] != -1)
{
return res[len][num][sta];
}
int u = up == 1 ? dig[len] : 9;
int i, j, k;
ll ans = 0;
for (i = 0; i <= u; i++)
{
if (sta >> i & 1)
{
ans += dfs(len - 1, num, change(sta, i), i == u&&up);
}
else
{
ans += dfs(len - 1, num + 1, change(sta, i), i == u&&up);
}
}
if (!up)
res[len][num][sta] = ans;
return ans;
}
ll solve(ll x)
{
mem(res, 0);
int len = 0;
while (x)
{
len++;
dig[len] = x % 10;
x /= 10;
}
mem(res, -1);
return dfs(len, 0, 1, 1);
}
int main()
{
cin >> L >> R >> k;
cout << solve(R) - solve(L - 1) << endl;
return 0;
}