HDU 5787 K-wolf Number 数位dp
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5787
K-wolf Number
Memory Limit: 65536/65536 K (Java/Others)
输出
For each test case output a line contains an integer.
样例
sample input
1 1 2
20 100 5sample output
1
72
题意
求L到R之间的所有的满足十进制表示中任意相邻的k位数字都不相同的数
题解
数位dp,注意处理下前导零。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#define bug(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
const int maxn = 20;
typedef __int64 LL;
//vector<int> 存放第i-k+1位到第i位的数
map<vector<int>, LL> dp[maxn];
int k;
//判断第0到k-2是否与k-1相同
bool ok(const vector<int>& ve) {
int last = ve[k - 1];
for (int i = 0; i < k - 1; i++) {
if (last == ve[i]) return false;
}
return true;
}
int arr[maxn],tot;
//ismax标记表示前驱是否是边界值,为true代表前驱都是边界值,为false则说明前驱已经小于边界了,这一位可以任意取了。
//iszer表示前驱是否都为0,即前面几位是否都为0
//vec记录的是前驱的结尾的k位
LL dfs(int len,vector<int> vec, bool ismax,bool iszer) {
if (len == 0) {
//递归边界,这说明前驱都合法了
return 1LL;
}
if (!ismax&&dp[len].count(vec)) return dp[len][vec];
LL res = 0;
int ed = ismax ? arr[len] : 9;
vector<int> ve;
for (int i = 1; i < vec.size(); i++) {
//这里吧前导零的部分贴成负数,防止当成真正的0来判。
if (iszer) ve.push_back(-i);
else ve.push_back(vec[i]);
}
for (int i = 0; i <= ed; i++) {
ve.push_back(i);
if (ok(ve)) {
res += dfs(len - 1, ve, ismax&&i == ed,iszer&&i==0);
}
ve.pop_back();
}
return ismax ? res : dp[len][vec] = res;
}
LL solve(LL x) {
tot = 0;
while (x) { arr[++tot] = x % 10; x /= 10; }
vector<int> vec;
for (int i = 1; i <= k; i++) vec.push_back(-i);
return dfs(tot, vec, true,true);
}
void init() {
for (int i = 0; i < maxn; i++) dp[i].clear();
}
int main() {
LL x, y;
init();
while (scanf("%I64d%I64d%d",&x,&y,&k)==3) {
printf("%I64d\n", solve(y)-solve(x-1));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步