湘潭大学OJ1131凹数

凹数

题目描述

如果一个十进制数的数码从左到右是先严格单调下降,然后严格单调上升,我们称这个数为凹数。比如说43212,这个数数码从4到1,然后从1到2,为一个凹数;另外比如4352,这个数从4到3,然后从3到5,然后又从5到2,所以不是个凹数。请计算在[a,b](100<=a<=b<1,000,000)之间有多少个凹数。

Time Limit : 1000 MS Memory Limit : 65536 KB

输入 第一行是一个整数N,表示样例的个数。 以后每行两个整数a和b。

输出 每行输出一个样例的结果

Sample Input
2
100 110
1000 1000000
Sample Output
9
23532

解题思路

给定a,b,遍历a,b之间所有的数,用一个数组将每一个数的每一位存起来,然后判断是否满足先严格单调下降,再严格单调递增,如何判断呢?我的思路是,因为数字最大为1000000,所以可以直接遍历储存数的数组,找到最小的数字所在的位置min,然后从第1位到min,判断是否严格单调下降,然后从min+1到最后一位,判断是否严格单调上升。

在将一个数的每一位存到数组里面时,是从个位到最高位进行存储的,但是其实正着存和倒着存是一样的,因为都是先严格单调下降,再严格单调上升。所以存储时就可以按照比较简单的从个位开始存。如下

int j = 0;
while(x>0) {
	j++;
	a[j] = x%10;
	x /= 10;
}

但是如果每个样例中,都去遍历a到b之间的所有的数字,因为题目没有给出样例个数的范围,所以我们猜测是可能会超时的。事实证明,确实是会,因为我第一次就是那么做的。

所以我们就想到了之前计算区间内素数个数的问题,我们用素数打表加前缀和简化了循环。所以在这里,我们也可以用前缀和的方式,用数组an[ ] 存储下标这个数前面(包括这个数)的总的凹数的个数,然后题目给定a,b,我们就可以用an[b] - an[a-1]来得到a,b之间凹数的个数。

代码如下

#include<bits/stdc++.h>
using namespace std;
int an[1000010];
int main() {
	an[99] = 0;//因为给定的a,b最小为100
	for(int i = 100; i<= 1000000; i++) {
		int s[10] = {0};//s数组存储每个数字每一位(倒着存储)
		int j = 0;
		int x = i;//不能直接用i操作,因为i要参与外部的循环
		while(x>0) {
			j++;
			s[j] = x%10;
			x /= 10;
		}
		int min = 10;
		for(int k = 1; k<= j; k++) {
			if(s[k] < s[min]) min = k; //找到最小数的位置
		}
		if(min == 1 || min == j) { //最小值不能在第一位或者最后一位
			an[i] = an[i-1];
			continue;
		}
		s[0] = 10;//因为后面会出现 k-1的情况,所以给s[0]赋个值,每一位数字最大是9,所以要保证两端较大,给定一个10
		int flag = 1;
		for(int k = 1; k<= min; k++) {
			if(s[k]>=s[k-1]) flag = 0; 
		}
		for(int k = min+1; k<= j; k++) {
			if(s[k]<=s[k-1]) flag = 0;
		}
		if(flag) an[i] = an[i-1]+1;
		else if(!flag) an[i] = an[i-1];
	}
	int n;
	scanf("%d",&n);
	while(n--) {
		int a,b;
		scanf("%d%d",&a,&b);
		printf("%d\n",an[b]-an[a-1]);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43966538/article/details/106395919