板题 hdu2089
题目意思,输出某个给定区间(给定左和右)区间中满足一下条件的数,不含数字4 不含连续的62,(分开的6 和 2 是允许的),输出答案。
- 直接数字打表可以解
- 利用itoa打表也可以
- 利用数位dp
利用数位dp解法
1、利用前缀和,注意最后输出的时候是r-(l-1),不是r-l,这样没有排除左端点的数
2、分别计算两个端点前面满足条件的数的个数
3、计算的时候利用dfs碰到不合法的数就不往下搜,合法的话就往下搜,搜的越深位数越小,直到最后的那一层是个位了
4、注意最后一层的遍历区间范围的问题,最后一层可能会碰到不能遍历到9 ,必然就会超过范围,于是在最后一位就用一个判断,如果是最后一位的话遍历范围就设置为当前这个数,不是最后一位统一都设成9,即由0遍历到9。
//
// main.cpp
// 数位dp_模板_m
//
// Created by 陈冉飞 on 2019/8/6.
// Copyright © 2019 陈冉飞. All rights reserved.
//
#include <iostream>
#include <cstring>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
typedef long long ll;
int digit[105];
int dp[10][2];
int dfs(int len,bool is_six, bool limit){
if (len == 0) {
return 1;
}
if (!limit && dp[len][is_six]) {
return dp[len][is_six];
}
int cnt = 0;
//不是最后一位的话就用9,然后从1到9,是最后一位的话就用最后一位的那个数,即digit[len]
int maxx = (limit ? digit[len]:9);
for (int i = 0; i <= maxx; i++) {
//两种情况
if (i == 4 || (i == 2 && is_six)) continue;
//如果当前位置为6,则等于这个位的状态往前传1
if (i == 6) cnt += dfs(len-1, true, limit&&(i == maxx));
else cnt += dfs(len - 1,false, limit&&(i == maxx));
}
return limit?cnt:dp[len][is_six] = cnt;
}
int trans(int n){
//初始化
int len = 0;
cl(digit,0);
cl(dp, 0);
while (n>0) {
digit[++len] = n%10;
n/=10;
}
return dfs(len, false,true);
}
int main(int argc, const char * argv[]) {
// cout<<trans(14)<<endl;
int l,r;
while (~scanf("%d%d",&l,&r)&&l != 0) {
// cout<<trans(r)-trans(l)<<endl;//不是r-l
cout<<trans(r)-trans(l-1)<<endl;
}
return 0;
}
数字itoa 然后遍历字串然后再看,(0<n≤m<1000000) 然后每次用itoa转换成string,然后就用string中判断是否字串的函数
//
// main.cpp
// hdu2089_itoa_打表
//
// Created by 陈冉飞 on 2019/8/6.
// Copyright © 2019 陈冉飞. All rights reserved.
//
#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <stdlib.h>
using namespace std;
typedef long long ll;
int ans[1000050];
int main(int argc, const char * argv[]) {
// ans[0] = 0;
// int a = 271;
// char temstr[1000050];
// sprintf(temstr, "%d", a);
char temstr[1000050] = {'2','7','1'};
//
// if (strstr(temstr, "71") == NULL) {
// cout<<"404"<<endl;
// }else cout<<"yes"<<endl;
ans[0] = 0;
char temstr[1000050];
for (int i = 1; i <= 1000000; i++) {
sprintf(temstr, "%d",i);
if (strstr(temstr,"4") == NULL &&strstr(temstr, "62") == NULL) {
ans[i] = ans[i-1]+1;
}else ans[i] = ans[i-1];
}
// for (int i = 0; i < 1000; i++) {
// cout<<i<<" "<<ans[i]<<endl;
// }
int l,r;
while (~scanf("%d%d",&l,&r)&&l != 0) {
cout<<ans[r]-ans[l-1]<<endl;
}
// for (int i = 1; i <= 1000; i++) {
// sprintf(temstr, "%d", i);
// //strstr只是char数组的功能
// if (strstr(temstr, "4") == NULL && strstr(temstr ,"62" == NULL) {
// ans
// }
cout<<temstr<<endl;
// }
//
// int i = 90;
// temstr = to_string(i);
// cout<<temstr<<endl;
return 0;
}
由于xcode无论调用什么库函数也没法用itoa 所以最后查到了sprintf这个方法来吧int转换成char数组。注意判断子字串的strstr方法应用对象为char数组。
int main(int argc, const char * argv[]) {
ans[0] = 0;
char temstr[1000050];
for (int i = 1; i <= 1000000; i++) {
sprintf(temstr, "%d",i);
if (strstr(temstr,"4") == NULL &&strstr(temstr, "62") == NULL) {
ans[i] = ans[i-1]+1;
}else ans[i] = ans[i-1];
}
int l,r;
while (~scanf("%d%d",&l,&r)&&l != 0) {
cout<<ans[r]-ans[l-1]<<endl;
}
return 0;
}