不吉利的数(动态规划)

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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值