[COCI2006-2007#6] V
前言
赛时联想到了讲的一道题认为不可以使用数位
思路
首先我们用数位
考虑倍数的本质, 我们考虑套路的转移模
然后你发现, 我们有简单的
同常规的数位
稍微特殊的是如果当前还在前导零状态下, 无论
总时间复杂度
实现
框架#
数据点分治,
, 使用数位 , 使用暴力方法
数位
代码#
#include <bits/stdc++.h>
#define int long long
const int SZ = 10000;
const int MAXSZ = 15;
const int MAXVAL = 10000; // 记得改回来
int X, A, B;
bool S[10];
class BruteForces
{
private:
int st;
int ans = 0;
bool check(int x) {
while (x) { if (!S[x % 10]) return false; x /= 10; }
return true;
}
public:
void solve() {
st = (A % X) ? A / X + 1 : A / X; st *= X;
for (int i = st; i <= B; i += X) if (check(i)) ans++;
printf("%lld", ans);
}
} BF;
class Intelligence
{
private:
int num[MAXSZ];
int dp[MAXSZ][MAXVAL][2][2];
/*从高位往低位推的数位 dp 的记忆化搜索*/
int dfs(int pos, int m, bool lead, bool limit) {
int ans = 0;
if (!pos) return (!lead && !m); // 边界条件
if (~dp[pos][m][lead][limit]) return dp[pos][m][lead][limit];
int up = limit ? num[pos] : 9;
for (int i = 0; i <= up; i++) {
if (i == 0 && lead) { ans += dfs(pos - 1, (m * 10 + i) % X, true, (i == up) & limit); continue; } // 特殊的情况
if (!S[i]) continue; // 不使用违法数字
ans += dfs(pos - 1, (m * 10 + i) % X, false, (i == up) & limit);
}
return dp[pos][m][lead][limit] = ans;
}
int f(int x) {
int len = 0; // 递推数字串的长度
while (x) { num[++len] = x % 10; x /= 10; }
memset(dp, -1, sizeof(dp)); // 表示没有处理过, 而非初值(这点跟树形 dp 不同)
return dfs(len, 0, true, true); // 传统
}
public:
void solve() {
printf("%lld", f(B) - f(A - 1));
}
} It;
signed main()
{
scanf("%lld %lld %lld", &X, &A, &B);
std::string a; std::cin >> a;
for (int i = 0; i < a.length(); i++) S[a[i] - '0'] = true;
if (X > SZ) BF.solve();
else It.solve();
return 0;
}
总结
根号分治思想非常好玩
枚举倍数的常见转移
vivo 50
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话