『程设解体报告』9的统计(含压位高精度模板)、倒数问题、识别条形码,编程珠玑(含o(n)优化)

9的统计


众所周知,琪露诺(チルノ,Cirno)是幻想郷 (げんそうきょう)中首屈一指的天才,可以说⑨就是她的代名词。


然而如今,她遇到了一个和⑨有关的难题。你能帮助她么?


题目是这样的,给出两个数 a 和 b (0 <= a <= b <= 10^10000),求 a 到 b 之间(包括a和b)的数字中,有多少个数字是包含9的(例如 19,910 等都是包含9的数字)。


输入


第一行为一个数字 T (0 < T <= 100) 表示数据组数。
之后的 T 行,每行包含两个数 a 和 b (0 <= a <= b <= 10^10000)。


输出


对每组数据输入,输出一个数字,表示 a 到 b 之间的数字中(包括a和b),有多少个数字是包含9的。(注意:答案可能很大)


这道题思路懒得写了,但是因为数据量太大,需要用到压位高精度,所以提供几个亿进制高精度模板

高精度 * 低精度

void mul(int *x, int d)
{
	int i, l = INF - 1;
	while (x[l] == 0 && l > 0)
	{
		l--;
	}
	l++;
	for (i = 0; i < l; i++)
	{
		x[i] = x[i] * d;
	}
	l++;
	for (i = 0; i < l; i++)
	{
		x[i + 1] += x[i] / 100000000;
		x[i] = x[i] % 100000000;
	}
}

高精度 + 高精度

void plus(int *x, int *y)
{
	int i;
	for (i = 0; i < INF; i++)
	{
		x[i] += y[i];
		if (x[i] >= 100000000)
		{
			x[i + 1]++;
			x[i] -= 100000000;
		}
	}
}

高精度 - 高精度

void minus(int *x, int *y, int *z)
{
	int i;
	for (i = 0; i < INF; i++)
	{
		z[i] += x[i] - y[i];
		if (z[i] < 0)
		{
			z[i + 1]--;
			z[i] += 100000000;
		}
	}
}



倒数问题


一个正整数的倒数是1除以那个整数。举例来说,37 的倒数是 1/37。有些正整数的倒数是可以用十进制的有限不循环小数表示的,这些正整数包括:


10 的幂;
2 的幂;
2 的幂并跟着数个 0;
5 的幂;
5 的幂并跟着数个 0。
你的任务是求出这样一些整数的倒数,并用十进制表示出来。


输入
输入的第一行是要处理的正整数的个数,后面每一行输入一个正整数。每一个正整数都符合以下条件:


都会从行首开始,
其第一列的数字不为 0,
最多包含 72 个数字。
输出
对于每一个正整数,输出以精确的十进制表示的该数的倒数。每个结果一行。

测试输入

4
4
100
6250000
10485760
测试输出

0.25
0.01
0.00000016
0.000000095367431640625


给出的数a满足这个条件

a = (2 ^ n) * (5 ^ m)

那么则存在一个数b

b = (2 ^ m) * (5 ^ n)

使得a * b = 10 ^ ( n + m)


也就是说对于给出的a,求出n和m

这里就需要高精度的除法,但是这里因为都是除的2或者5并且肯定能除到1的,还是很好写的,模拟一下试除法,便可以搞定,

可以把除法的写一个模板,然后就直接调用啦

顺便贴一个费大神写的板吧,接口是正常顺序的字符串和除数

void div(char *x, int d)
{
	int i, l, y, z = 0;
	int a[205];
	memset(a, 0, sizeof(a));
	l = strlen(x);
	for (i = 0; i < l; i++)
	a[i] = x[i] - '0';
	for (i = 0; i < l; i++)
	{
		if (a[i] < d)
		{
			a[i + 1] += a[i] * 10;
			a[i] = 0;
			continue;
		}
		y = a[i] % d;
		a[i + 1] += y * 10;
		a[i] = a[i] / d;
	}
	for (i = 0; i < l; i++)
	{
		if (a[i] != 0)
		{
			z = i;
			break;
		}
	}
	for (i = 0; i < l - z; i++)
		x[i] = a[i + z] + '0';
	x[l - z] = '\0';
}

用这个方法把n和m求出来后,就用高精度乘法求b = (2 ^ m) * (5 ^ n)啦,

高精度乘法的模板就不放出来了,虽然网上有好多高精度乘法的板,但因为这里的一个乘数只有1位,所以可以自己写一个更加高效的

不过因为最后只需要把两个幂相乘,也就可以把2的250次幂以及5的150次幂的结果打表,然后用一个乘法就能搞定啦;


把b也求出来后,然后做一下增添和去除0的处理,然后就能愉快的输出啦,祝大家AC



识别条形码

软件学院2011级的院花牟黑黑同学是一只黑富美,她一生气就会去学服疯狂购物~,但她有一个癖好就是识别条形码(天赋技能,这是人物设定而已。。。),于是她想把自己买的商品的条形码都识别出来。


在生活中,条形码经常用来标志物品的信息。条形码是由黑白相间的条组成的。条的宽度有两种,我们可以认为窄的代表0,宽的代表1。本题中设定宽条的宽度是窄条的两倍。


牟黑黑拥有很强的DIY精神,他决定做一个条形码识别工具。首先他完成了图像识别部分,得到了一系列条的宽度。他希望将这些宽度识别为一个01串。本来这是一个非常简单的任务,可是由于牟黑黑在识别的时候会有误差,使得问题变得没那么简单了。不过牟黑黑认为测量得到的结果最多比真实值大或小5%。请你帮忙完成这个识别程序。已知条形码中至少有一个是宽条。


输入第一行为一个数字n(n<20),表示牟黑黑识别出了n个条。
第二行为n个正整数,均不大于10^8。
如果合法,输出为一个长度为n的01串。否则输出“Bad Barcodes”


测试输入

4
99 105 200 199
测试输出

0011


这道题的n最大为20,让我很费解,并且每一个数都小于10^8,

所以方法就很多啦,可以o(n)的方法过的,找出最大值和最小值,然后每一个数判断范围就可以了吧,

比较好的处理方法是,所有数都读成double,然后在计算比值时就很方便啦,

另外,如果所有条码都是相同的话,全部条码都视为宽条码(题目中有说至少一个宽条码)

附一个Eureka大神的思路

 
首先求出输入中的最大值max和最小值min,通过min/0.95 >= max/1.05来判定如果都是宽条的话是否合法。


然后就必然01都有了。假设输入合法,此时可以设half = (max + min) / 2,比half 大就是1,小就是0。


此时我们将所有的窄条都乘2,那么此时就都是宽条了,和第一种情况相同,判定即可。


这样子的方法,即使条形码不止两种也能识别。



编程珠玑

你有一条项链,它由 N 个随机排列的红、白和蓝色的珠子组成(3<=N<=350)。下面的例子展示了两条 N=29 时的项链:


             1 2                              1 2
           r b b r                           b r r b
          r         b                       b         b
         r           r                     b           r
        r             r                   w             r
       b               r                 w               w
      b                 b               r                 r
      b                 b               b                 b
      b                 b               r                 b
       r               r                 b               r
        b             r                   r             r
         b           r                     r           r
           r       r                         r       b
             r b r                            r r w
          Figure A                     Figure B
                        r red bead
                        b blue bead
                        w white bead
项链上的第一个和第二个珠子已经在图中标出了。
图 A 也可以用一个由 b 和 r 组成的字符串直接表示,b 代表蓝色而 r 代表红色,如下所示:brbrrrbbbrrrrrbrrbbrbbbbrrrrb。


假设你想从项链的某处将它截断拉直;接着从一端向另外一端数收集同颜色的珠子,直到碰到一个不同颜色的珠子为止;然后再从另外一端做同样的操作。(一端收集的珠子颜色可以不同于另一端的。)


请想办法找到一个截断项链的位置,能够让我们尽量多地收集到同色的珠子。


例子
如图 A 中的项链,从第 9 和第 10 个或者第 24 和 第 25 个珠子中间截断,则我们可以收集到 8 个珠子。


图 B 中的项链有白色的珠子,当遇到白色的珠子时,它既可以作为蓝色的珠子看待,也可以作为红色的珠子看待,由收集珠子时的需求决定。包含有白色珠子的项链则会由 r、b 和 w 字符组成的字符串来表示。


请编写一个程序计算从某条项链中能够收集到多少个珠子。


输入格式
第一行: N,项链上珠子的个数


第二行:一个字符串,长度为 N,由 r、b 和 w字符组成


输入样例

29
wwwbbrwrbrbrrbrbrwrwwrbwrwrrb


输出格式
输出一行字符,它应该包含了计算出的结果。


输出样例
11


这个题呢,数据量也很小,最长才350啊混蛋,o(n^2)的暴力方法完全可以做的

本来还想着找o(n)的方法,结果看到这数据量,直接给暴力了,后面再慢慢想优化吧

首先这是一个环形的项链,并且可以从两端跑的,

在读入的时候可以做这样的处理,

将项链读入之后,再接着在后面重复一遍,就相当于两条项链连到一起了(当然如果最后计算结果大于项链长度的话,那么正确结果应该为项链长度)

读入两条项链之后,就可以开始枚举中点了

注意白色的也要枚举

两个方向各使用一个颜色标记,最开始为空,直到遇到不是白色的珠子后,标记颜色,然后接着判断

就这么不停的枚举啊,然后就找到最大值了。

需要注意的就是起点是白色这种情况的处理方法。


优化方法(o(n)复杂度)

优化原理就是每次遍历后的左右的距离储存起来,然后在后面珠子往前后遍历时就可以愉快地利用以前的结果了

可以开两个数组,一个记录左边的距离,另外一个记录右边的距离

如果该珠子不为白色,那么记录下的距离为一共能到的距离

如果为白色,那么就记录往该方向最多能有多少个白色的,


具体方法

在遍历到某一个中点时候,比如在i和i+1中间剪断

然后判断i - 1与i是否颜色匹配,如果匹配,则加上i - 1处存的距离,如果i - 1为白色,则直接调取存储的距离,判断该方向出现的第一个非白色是否匹配,如果匹配,则加上存储的距离

向右同理


ps:奈何这道题目数据量太小,没人去想优化方法啊


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值