一定要定义dp为好几个状态吗

P4124 [CQOI2016] 手机号码

```cpp void solve(){ long long a, b; cin >> a >> b; long long dp[20][20][20]; vector<int> num; function<long long(int, int, int, bool, bool, bool, bool, bool)> dfs = [&](int pos, int pre, int sec_pre, bool lead, bool limit, bool has8, bool has4, bool con)->long long{ // cout << pos << " " << pre << " " << sec_pre << endl; if (has8 && has4){ return 0; } if (pos == 0){ return con; } if (limit == false && dp[pos][pre][sec_pre] != -1){ return dp[pos][pre][sec_pre]; } long long res = 0; int up = (limit == true ? num[pos] : 9); for (int i = 0; i <= up; ++i){ if (lead == true && i == 0){ continue; } res += dfs(pos - 1, i, pre, false, limit && (i == up), has8 || (i == 8), has4 || (i == 4), con || (i == pre && i == sec_pre)); } if (!limit){ dp[pos][pre][sec_pre] = res; } return res; }; auto cal = [&](long long x)->long long{ num.resize(1); while (x){ num.emplace_back(x % 10); x /= 10; } memset(dp, -1, sizeof(dp)); if (int(num.size()) != 12){ return 0; } return dfs(int(num.size()) - 1, 0, 0, true, true, false, false, false); }; cout << cal(b) - cal(a - 1) << '\n'; } 这是过不了的代码,加了3个维度后就可以了 ```
by Touris2ts @ 2024-01-15 21:51:17


```cpp #include <bits/stdc++.h> using namespace std; #define dbg std::cout << "----------------------------------------" << std::endl; constexpr array<long long, 63> pow2_values{1ll,2ll,4ll,8ll,16ll,32ll,64ll,128ll,256ll,512ll,1024ll,2048ll,4096ll,8192ll,16384ll,32768ll,65536ll,131072ll,262144ll,524288ll,1048576ll,2097152ll,4194304ll, 8388608ll,16777216ll,33554432ll,67108864ll,134217728ll,268435456ll,536870912ll,1073741824ll,2147483648ll,4294967296ll,8589934592ll,17179869184ll,34359738368ll,68719476736ll, 137438953472ll,274877906944ll,549755813888ll,1099511627776ll,2199023255552ll,4398046511104ll,8796093022208ll,17592186044416ll,35184372088832ll,70368744177664ll,140737488355328ll, 281474976710656ll,562949953421312ll,1125899906842624ll,2251799813685248ll,4503599627370496ll,9007199254740992ll,18014398509481984ll,36028797018963968ll,72057594037927936ll, 144115188075855872ll,288230376151711744ll,576460752303423488ll,1152921504606846976ll,2305843009213693952ll,4611686018427387904ll }; constexpr array<int, 4> dx {-1, 1, 0, 0}; constexpr array<int, 4> dy {0, 0, -1, 1}; constexpr array<int, 8> dx2 {-1, -1, 0, 1, 1, 1, 0, -1}; constexpr array<int, 8> dy2 {0, -1, -1, -1, 0, 1, 1, 1}; long long fastPower(long long a, long long b, long long mod = int(1e9 + 7)){long long rst = 1;while (b){if (b & 1){rst = rst * a % mod;}b >>= 1;a = a * a % mod;} return rst;} inline long long fermatInverse(long long a, long long mod){ return fastPower(a, mod - 2, mod); } inline long long lcm(long long a, long long b){return a / __gcd(a, b) * b;} template<typename T, typename U> inline bool changeMax(T& a, U b){return a < b ? a = b, true : false;} template<typename T, typename U> inline bool changeMin(T& a, U b){return a > b ? a = b, true : false;} void preProcess(){ } void solve(){ long long a, b; cin >> a >> b; long long dp[20][20][20][2][2][2]; vector<int> num; function<long long(int, int, int, bool, bool, bool, bool, bool)> dfs = [&](int pos, int pre, int sec_pre, bool lead, bool limit, bool has8, bool has4, bool con)->long long{ // cout << pos << " " << pre << " " << sec_pre << endl; if (has8 && has4){ return 0; } if (pos == 0){ return con; } if (limit == false && dp[pos][pre][sec_pre][con][has8][has4] != -1){ return dp[pos][pre][sec_pre][con][has8][has4]; } long long res = 0; int up = (limit == true ? num[pos] : 9); for (int i = 0; i <= up; ++i){ if (lead == true && i == 0){ continue; } res += dfs(pos - 1, i, pre, false, limit && (i == up), has8 || (i == 8), has4 || (i == 4), con || (i == pre && i == sec_pre)); } if (!limit){ dp[pos][pre][sec_pre][con][has8][has4] = res; } return res; }; auto cal = [&](long long x)->long long{ num.resize(1); while (x){ num.emplace_back(x % 10); x /= 10; } memset(dp, -1, sizeof(dp)); if (int(num.size()) != 12){ return 0; } return dfs(int(num.size()) - 1, 0, 0, true, true, false, false, false); }; cout << cal(b) - cal(a - 1) << '\n'; } int main(){ ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int tc = 1; // cin >> tc; preProcess(); while (tc--){ solve(); } return 0; } ```
by Touris2ts @ 2024-01-15 21:51:45


为什么只有pos, pre, pre的pre三个变量作为dp的转移状态不行,还要加上8,4,连续这3个维度呢?如何理解这种差异,求佬发表
by Touris2ts @ 2024-01-15 21:52:42


@[Touris2ts](/user/1180143) 我好像懂了,这么设状态,是因为假如我们的pos一共有11位,现在在第7位。虽然第pos = 8, pre = a, sec_pre =b已经被计算过了,但是第11位是什么,我们不知道,我们必须定义4出现跟8出现的情况才能确保第11位的数字出现,跟我们之前计算过的状态不冲突(也就是说之前计算的状态是可用的),如果之前计算的时候第11位是4,但是现在第11位是2,那么之前计算的状态就失效了。 动态规划的核心是历史计算结果避免重复计算,但是我们现在要利用的结果如果不能保证跟历史计算的结果 状态完全相同,那么这个结果就不能利用了。
by Touris2ts @ 2024-01-15 22:05:28


@[Touris2ts](/user/1180143) 你的理解是正确的,谢谢大佬
by Touris2ts @ 2024-01-15 22:05:41


@[Touris2ts](/user/1180143) 自娱自乐上了
by 7The_shy @ 2024-01-19 11:07:32


|