Description
大家知道,东方国家认为4这个数字不吉利,西方国家认为13这个数字不吉利。有一个外星球的居民同我们地球人类似,认为7这个数字不吉利。基于这个认识,这些外星居民把任何一个含有7的数字都认为是不吉利的,比如:7,17,876,1751,……。现在这些外星居民想知道在任意两个数A,B(A≤B)之间有多少个不吉利的数,但是他们又特别迟钝,因此需要你的帮助。
输入
输入两个整数A、B,并用空格进行间隔(0≤A≤B≤10e50)。
输出
输出单个整数,表示[A,B]之间不吉利的数的个数。
样例输入
60 80
样例输出
11
思路
看规模很大,暴力肯定超市。所以考虑动态规划,先把x位数以内的包含7的数求出个数来,存放在cnt[]数组里面。再利用差分的思想:求出0-B的含7的数 和 0-A中含7的数,相减即可。注意如果A是不吉利的数,答案要加上它。
初始化cnt[]
ull cnt[100];
bool vis[100];
void init() {
int total = 19;//处理的规模
cnt[0] = 0;
cnt[1] = 1;
//处理cnt[weishu]
for (int weishu = 2; weishu <= total; weishu++) {
memset(vis, 0, sizeof vis);
//cnt[weishu] = pow(10, weishu - 1);
//vis[0] = 1;
for (int j = 1; j <= weishu; j++)//j代表当前固定的是哪一位
{
ull tem = 1;//tem来统计固定当前位的数的个数
for (int k = 1; k <= weishu; k++) {//遍历扫描每一位的填充数
if (k == j) continue;//跳过固定位
if (vis[k]) {
if (k == 1) tem *= 8;
else tem *= 9;
}
else {
tem *= 10;
}
}
//cout << "---" << tem << endl;
cnt[weishu] += tem;
vis[j] = 1;//固定第j位
}
cnt[weishu] += cnt[weishu - 1];
}
}
计数函数count
ull count(string b,int lenb) {//考虑b
ull res = 0;
for (int pos = 0; pos <lenb; pos++)
{
if (b[pos] > '7') {
res += (b[pos] - '0' - 1)*cnt[lenb - pos - 1] + pow(10, lenb - pos - 1);
//cout << "-" << res << endl;
//break;
}
else if (b[pos] == '7') {
res += 7 * cnt[lenb - pos - 1];
ull tem = 0;//本身00000
for (int j = pos+1; j < lenb; j++)
{
tem = tem * 10 + (b[j] - '0');
}
tem++;
res += tem;
//cout << "--" << res << endl;
break;
}
else {
if (pos == lenb - 1) continue;
res += cnt[lenb - pos - 1] * (b[pos] - '0');
//cout << "-------" << cnt[lenb - pos] * (b[pos - 1] - '0') << endl;
//cout << "---" << res << endl;
}
}
//cout << res << endl;
return res;
}
完整代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
typedef unsigned long long ull;
using namespace std;
char a[100], b[100];
ull cnt[100],ans;
bool vis[100];
void init() {
int total = 19;//处理的规模
cnt[0] = 0;
cnt[1] = 1;
//处理cnt[weishu]
for (int weishu = 2; weishu <= total; weishu++) {
memset(vis, 0, sizeof vis);
//cnt[weishu] = pow(10, weishu - 1);
//vis[0] = 1;
for (int j = 1; j <= weishu; j++)//j代表当前固定的是哪一位
{
ull tem = 1;//tem来统计固定当前位的数的个数
for (int k = 1; k <= weishu; k++) {//遍历扫描每一位的填充数
if (k == j) continue;//跳过固定位
if (vis[k]) {
if (k == 1) tem *= 8;
else tem *= 9;
}
else {
tem *= 10;
}
}
//cout << "---" << tem << endl;
cnt[weishu] += tem;
vis[j] = 1;//固定第j位
}
cnt[weishu] += cnt[weishu - 1];
}
}
ull count(string b,int lenb) {//考虑b
ull res = 0;
for (int pos = 0; pos <lenb; pos++)
{
if (b[pos] > '7') {
res += (b[pos] - '0' - 1)*cnt[lenb - pos - 1] + pow(10, lenb - pos - 1);
//cout << "-" << res << endl;
//break;
}
else if (b[pos] == '7') {
res += 7 * cnt[lenb - pos - 1];
ull tem = 0;//本身00000
for (int j = pos+1; j < lenb; j++)
{
tem = tem * 10 + (b[j] - '0');
}
tem++;
res += tem;
//cout << "--" << res << endl;
break;
}
else {
if (pos == lenb - 1) continue;
res += cnt[lenb - pos - 1] * (b[pos] - '0');
//cout << "-------" << cnt[lenb - pos] * (b[pos - 1] - '0') << endl;
//cout << "---" << res << endl;
}
}
//cout << res << endl;
return res;
}
ull f2() {
printf("f2:\n");
ull a, b;
scanf("%lld %lld", &a, &b);
char num[10];
ull ans1 = 0;
for (int i = a; i <= b; i++)
{
sprintf(num, "%d", i);
int len = strlen(num);
for (int j = 0; j < len; j++)
{
if (num[j] == '7') {
//cout << "YES:" << i << endl;
ans1++;
break;
}
}
}
//printf("%lld\n", ans1);
return ans1;
}
ull f1() {
//printf("f1:\n");
scanf("%s %s", &a, &b);
ans = 0;
int lena = strlen(a);
int lenb = strlen(b);
ans = count(b,lenb) - count(a,lena);
for (int i = 0; i < lena; i++)
{
if (a[i] == '7') {
ans++;
break;
}
}
//printf("%lld\n", ans);
return ans;
}
int main() {
init();//初始化cnt数组
//for (int i = 0; i < 10; i++)
//{
// printf("%d->%lld\n", i, cnt[i]);
//}
//while (1) {
//cout << "f1:" << endl;
//f1();//动态规划
//cout << "f2:" << endl;
//f2();//暴力
//cout << endl;
printf("%lld\n", f1());
//}
return 0;
}