【分治算法】2011

        标题解释:名为分治算法,实为顺序结构。欲知何出此言,且听下文分解。

        前言:这次考试稳(wan)了,这次考试班级排名保二(位数)了,但不管怎么说,还是要冷静下来。虽然明天就能出成绩了,但今晚还是开一道题。上题目:


[问题描述]

       现给出正整数n,求出2011^n的后四位。

[输入]

       第一行一个正整数t,表示有t组数据,其中1\leq t\leq 10^3

       接下来t行,每行一个正整数n

[输出]

       共t行,每个n对应的结果占一行。如果不足四位,去掉前导零。

[样例输入]

3
5
28
792

[样例输出]

1051
81
5521

[数据规模与约定]

        对于100%的数据,1\leq n\leq 10^{200}


        第一印象:1\leq n\leq 10^{200} ?是不是多打了个0?这让人怎么算呀?淡定,淡定,开始分析。

        这是一道分治算法题,至于10200次方就要用到高精度算法了。我自己试着写了写,半个小时过去了代码还是一片狼藉,在这里就不展示了。我就另想思路。

        我在上一期说过,事物的发展有其规律,这道题是不是也有规律?

        既然只要求最后四位数,那我们就自始至终只考虑最后四位数。只有四位数,也就是说最多有10000种答案,那就必定存在循环。至于多少次一循环呢?我们不妨写个小程序试一下。

#include <cstdio>

	int a = 2011, p;
	
	int main() {
		do {
			a = a * 2011 % 10000;
			p++;
		}
		while (a != 2011);
		printf("%d", p);
	}

        跑一下程序,发现500次一循环。换句话说,n500取模后,得到的结果仍然相同!

        能想到这里,问题就解决的差不多了——相当于把n的范围从10200次方缩小到了500!现在还差一个小问题:高精度数怎么对500取模?其实也很简单,我们可以先对1000取模(即取最后三位),再对500取模,这样就会非常省事!

        剩下的就来硬算吧!代码真的很好写。讲解版AC代码如下:

#include <cstdio>
#include <cstring>

	int t, m, r, len;
	char s[520];

	int main() {
		scanf("%d ", &t); // 注意这里要多读入一个空格
		while (t--) {
			r = 0; m = 1; // 初始化
			gets(s);
			len = strlen(s);
			for (int i = 3; i > 0; i--) // 取最后三位数,当然也可能不足三位,此方法通用
			    if (len - i >= 0)
			        r = r * 10 + s[len - i] - '0';
			r %= 500;
			for (int i = 1; i <= r; i++)
				m = m * 2011 % 10000; // 暴力开算
			printf("%d\n", m);
		}
		return 0;
	}

        原版代码:

#include <cstdio>
#include <cstring>

	int t, m, r, len;
	char s[520];

	int main() {
		scanf("%d ", &t);
		while (t--) {
			r = 0;
			m = 1;
			gets(s);
			len = strlen(s);
			for (int i = 3; i > 0; i--)
			    if (len - i >= 0)
			        r = r * 10 + s[len - i] - '0';
			r %= 500;
			for (int i = 1; i <= r; i++)
				m = m * 2011 % 10000;
			printf("%d\n", m);
		}
		return 0;
	}

        并以简短的代码冲上本题排行榜第一(我这还是标准格式呢)。

        这题就讲到这里啦!好了,现在我又陷入低沉的情绪了,毕竟这次考的啥也不是,以后是该好好学了,如果这样的话以后发布代码就会少了,但我对代码的热爱永远不会消散!最后,感谢大家的支持——我是汤圆,我们下期再见!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值