HDU 2089 不要62(数位DP,三种姿势)
ACM
题目地址:HDU 2089
题意:
中文题意,不解释。
分析:
- 100w的数据,暴力打表能过
- 先初始化dp数组,表示前i位的三种情况,再进行推算
- 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz)
代码:
1. 暴力 (以前写的)
/*
* Author: illuz <iilluzen[at]gmail.com>
* File: 2089_bf.cpp
* Create Date: 2014-03-31 20:28:46
* Descripton: brute force way
*/
#include <cstdio>
#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
const int N = 1000010;
int f[N], n, m;
bool check(int r) {
while (r) {
if (r % 10 == 4) return false;
if (r % 100 == 62) return false;
r /= 10;
}
return true;
}
void init() {
repf (i, 1, 1000000)
if (check(i))
f[i] = f[i - 1] + 1;
else
f[i] = f[i - 1];
}
int main()
{
init();
while (RII(n, m) && (n || m)) {
PIN(f[m] - f[n - 1]);
}
return 0;
}
2. DP_1
/*
* Author: illuz <iilluzen[at]gmail.com>
* File: 2089.cpp
* Create Date: 2014-07-26 09:55:48
* Descripton:
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define repd(i,a,b) for(int i=(a);i>=(b);i--)
const int N = 10;
int n, m;
int bits[N];
int dp[N][3]; // [len][x]
// 0->luck
// 1->luck and highest is 2
// 2->unluck
void init() {
dp[0][0] = 1; // len is 0 and luck is 1, becauses the dp[1][1] will equal it.
dp[0][1] = dp[0][1] = 0;
repf(i, 1, N - 1) {
dp[i][0] = dp[i - 1][0] * 9 // i-1_luck without 4
- dp[i - 1][1]; // and without 62
dp[i][1] = dp[i - 1][0]; // equal to i-1_luck_2 + '6'
dp[i][2] = dp[i - 1][2] * 10 // unluck is always unluck
+ dp[i - 1][0] // i-1_luck + '4'
+ dp[i - 1][1]; // i-1_luck_2 + '6'
}
}
int solve(int num) {
int len = 0, rec = num, ans, flag;
// get bits array
while (num) {
bits[++len] = num % 10;
num /= 10;
}
bits[len + 1] = 0;
ans = 0; // the unluck num
flag = 0; // if appear unluck
repd (i, len, 1) {
ans += dp[i - 1][2] * bits[i]; // unluck is always unluck
if (flag) { // if unluck appeared
ans += dp[i - 1][0] * bits[i]; // all luck become unluck
} else {
if (bits[i] > 4) {
ans += dp[i - 1][0]; // i-1_luck + '4'
}
if (bits[i] > 6) {
ans += dp[i - 1][1]; // i-1_luck_2 + '6'
}
if (bits[i + 1] == 6 && bits[i] > 2) {
ans += dp[i][1];
}
}
if (bits[i] == 4 || (bits[i + 1] == 6 && bits[i] == 2)) {
flag = 1;
}
}
return rec - ans;
}
int main() {
init();
while (~RII(n, m) && (n || m)) {
PIN(solve(m + 1) - solve(n));
}
return 0;
}
3. DP_2(DFS)
/*
* Author: illuz <iilluzen[at]gmail.com>
* File: 2089_dfs.cpp
* Create Date: 2014-07-26 15:21:12
* Descripton: dfs version
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)
const int N = 10;
int bits[N], dp[N][2]; // dp[i][is6] is the number of i-len digits with (if prevent number is 6), its digits are from 0-9
// the rest length, Is the prevent digit 6, Is the digit max
int dfs(int len, bool is6, bool ismax) {
if (len == 0)
return 1;
if (!ismax && dp[len][is6] >= 0) // dp
return dp[len][is6];
int cnt = 0, mmax = (ismax? bits[len] : 9);
for (int i = 0; i <= mmax; i++) {
if (i == 4 || is6 && i == 2) // unluck digit
continue;
cnt += dfs(len - 1, i == 6, ismax && i == mmax);
}
return ismax ? cnt : dp[len][is6] = cnt; // remember the result
}
int solve(int num) {
int len = 0;
while (num) {
bits[++len] = num % 10;
num /= 10;
}
return dfs(len, false, true);
}
int main() {
int n, m;
memset(dp, -1, sizeof(dp));
while (~scanf("%d%d", &n, &m) && (n || m)) {
PIN(solve(m) - solve(n - 1));
}
return 0;
}