P6371 [COCI2006-2007#6] V 题解
一个比较有趣的数位 DP。
考虑当 比较大的时候,可以暴力枚举 的所有倍数,判断是否可行,这个的复杂度是 的。这个过程类似根号分治,当 时暴力,我的做法中取 。
对于 ,考虑数位 DP。平凡的,只需要在 DP 的时候记录当前的数对 取模的结果即可。由于 ,所以数组一定开得下。
有一点需要注意,如果 不能用,要注意前导 仍可以用。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int LIM = 1e4;
const int N = 13;
long long x, a, b;
string s;
bool flag[N];
long long solve1()
{
for (auto& i : s) flag[i - '0'] = 1;
long long ans = 0LL;
for (long long i = x; i <= b; i += x)
{
if (i < a) continue;
string ss = to_string(i);
for (auto& i : ss)
{
if (!flag[i - '0'])
{
goto E;
}
}
ans++;
E:;
}
return ans;
}
long long dp[N][LIM + 5][2][2];
string p;
long long dfs(int u, long long r, bool flag, bool zgw)
{
if (~dp[u][r][flag][zgw]) return dp[u][r][flag][zgw];
dp[u][r][flag][zgw] = 0;
if (r == 0 && u == p.size())
{
if (!flag)
{
dp[u][r][flag][zgw] = 1;
}
}
if (u > p.size() - 1) return dp[u][r][flag][zgw];
int nowlim = (zgw ? p[u] - '0' : 9);
for (auto& i : s)
{
int gg = i - '0';
if (gg <= nowlim)
{
dp[u][r][flag][zgw] += dfs(u + 1, (r * 10LL + gg) % x, (flag && gg == 0), (zgw && gg == nowlim));
}
}
if (flag && s.find("0") == -1)
{
dp[u][r][flag][zgw] += dfs(u + 1, 0LL, 1, 0);
}
return dp[u][r][flag][zgw];
}
long long solve2()
{
p = to_string(b);
p = " " + p;
memset(dp, -1, sizeof dp);
long long ans1 = dfs(1, 0, 1, 1);
p.clear();
p = to_string(a - 1);
p = " " + p;
memset(dp, -1, sizeof dp);
long long ans2 = dfs(1, 0, 1, 1);
return ans1 - ans2;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> x >> a >> b >> s;
if (x > LIM) cout << solve1() << "\n";
else cout << solve2() << "\n";
return 0;
}

浙公网安备 33010602011771号