Sicily1020-大数求余算法及优化

Github最终优化代码: https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1020.c

题目如下:

1020. Big Integer

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB

Description

Long long ago, there was a super computer that could deal with VeryLongIntegers(no VeryLongInteger will be negative). Do you know how this computer stores the VeryLongIntegers? This computer has a set of n positive integers: b1,b2,...,bn, which is called a basis for the computer.

The basis satisfies two properties:
1) 1 < bi <= 1000 (1 <= i <= n),
2) gcd(bi,bj) = 1 (1 <= i,j <= n, i ≠ j).

Let M = b1*b2*...*bn

Given an integer x, which is nonegative and less than M, the ordered n-tuples (x mod b1, x mod b2, ..., x mod bn), which is called the representation of x, will be put into the computer.

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input.
Each test case contains three lines.
The first line contains an integer n(<=100).
The second line contains n integers: b1,b2,...,bn, which is the basis of the computer.
The third line contains a single VeryLongInteger x.

Each VeryLongInteger will be 400 or fewer characters in length, and will only contain digits (no VeryLongInteger will be negative).

Output

For each test case, print exactly one line -- the representation of x.
The output format is:(r1,r2,...,rn)

Sample Input

2

3
2 3 5
10

4
2 3 5 7
13

Sample Output

(0,1,0)
(1,1,3,6)

Problem Source

ZSUACM Team Member

博主刚看到这题目的时候,没怎么多想,写了个如下公式:

(x0*10^length-1 + x1*10^length-2 + ... + xlength-1*10^0)%b

=(x0*10^length-1%b + x1*10^length-2%b + ... + xlength-1*10^0%b)%b

然后这里关键是求出10^x%b出来。

注意到在求解10^x%b=(10%b * 10^x-1%b)%b,这里有一个明显的递归公式。

即,在求解10^x%b的时候已经包含了10^x-1%b的计算,而10^x-1%b的计算也会包含10^x-2%b的计算。

换句话说,我们可以实现求出需要的10^length%b,并用一个数组来保存每一步计算出来的10^x%b。

想出来的时候博主认为这样写已经效率很好了,没有重复计算,跑出来的结果是0.05s。

核心代码如下:

 1 for (i = 0; i < n; i++) {
 2     z = b[i];
 3     remember_arr[0] = 1;
 4
 5     temp = 10 % z;
 6     for (j = 1; j < length; j++) {
 7         remember_arr[j] = (temp * remember_arr[j - 1]) % z;
 8     }
 9
10     result[i] = 0;
11     count = length - 1;
12     for (j = 0; j < length; j++) {
13         result[i] += (((x[j] - 48) % z) * remember_arr[count--]) % z;
14     }
15     result[i] %= z;
16 }

然后,博主google发现有一种更快的写法,即用代码模拟人手算的过程,核心代码如下:

1 for (j = 0; j < length; j++)
2     result = (result * 10 + big_number[j]) % b;

用这种写法跑的是0.03s。

最后我们来思考一下,人手算的过程的借位都是10,为什么? 因为如果借位太多计算不过来,但是计算机不一样,对计算机来说,xx/b的计算和xxxxxxxxxxx/b的计算是一个原子性的操作,就是说,计算机有能力借更多的位。

我们看int最大大概10^10,那么如果一次借位10^9是不是大大减少了这个运算呢?

比如说,现在有长度为36的字符串,如果按原本的写法,要借位35次,换句话说,有35个求余计算,如果把这个字符串切成4个长度为9的字符串,然后以这些碎片为单位进行运算和借位的话,只需要借位运算4次。

更改了求余运算的基本运算长度之后,性能将大幅提高,最终结果为0.00s。

核心代码如下:

1 num_pieces = length / 9 + 1;
2 pieces[0] = str_to_int(p, length % 9);
3 p += length % 9;
4 for (i = 1; i < num_pieces; i++)
5     pieces[i] = str_to_int(p, 9), p += 9;
6 for (i = 0; i < n; i++)
7     r[i] = calculate_result(b[i]);

函数实现如下:

 1 int str_to_int(char *str, int l) {
 2     result = 0, j = 0;
 3     while (j < l)
 4         result = result * 10 + str[j++] - ‘0‘;
 5     return result;
 6 }
 7
 8 int calculate_result(int b) {
 9     t = 1000000000 % b;
10     result = 0;
11     for (j = 0; j < num_pieces; j++)
12         result = (result * t + pieces[j] % b) % b;
13     return result;
14 }
时间: 2024-11-09 12:42:06

Sicily1020-大数求余算法及优化的相关文章

POJ 2635 The Embarrassed Cryptographer(大数求余)

题意:给出一个大数,这个大数由两个素数相乘得到,让我们判断是否其中一个素数比L要小,如果两个都小,输出较小的那个. 分析:大数求余的方法:针对题目中的样例,143 11,我们可以这样算,1 % 11 = 1:      1×10 + 4 % 11 = 3:      3×10 + 3 % 11 = 0;我们可以把大数拆成小数去计算,同余膜定理保证了这个算法的这正确性,而且我们将进制进行一定的扩大也是正确的. 注意:素数打标需要优化,否则超时.   进制需要适当,100和1000都可以,10进制超

大数求余

1 /**2016中国大学生程序设计网络赛赛HDU 2 1001大数求余 3 */ 4 5 #include "iostream" 6 #include "cstdio" 7 #include "cstring" 8 using namespace std; 9 char s[100000002]; 10 int main() { 11 12 int t=1; 13 while(~scanf("%s", &s)) {

求余算法思想

求余实例: 求120650206除以11的余数 求解思想: 第一步:120650206/11=10968200.54545... 第二步:对上式结果向下取整,即直接舍去小数点后的数字, 即10968200 第三步:用向下取整后得到的数字乘以11, 即10968200*11=120650200 第四步:用上式结果减去被除数并取绝对值, 即|120650200-120650206|=6 下图是对(120650206+4)%11+1的Labview实现程序: 注:自己的一点小想法~~~低级别见笑!

nyoj 803 A/B Problem(大数除小数&amp;&amp;大数求余小数)

这道题 也就是大数除或者求模小数,不过听说java处理大数很方便,可是java学的一塌糊涂..有心人用java做吧 奉上c语言代码: #include <stdio.h> #include <string.h> int main() { char a[1000],c[1000],ch; int b,i,j,r; while(scanf("%s %c %d",a,&ch,&b)!=EOF)//a是存贮大数,ch存贮运算符,b是小数 { r=0; i

POJ 2305大数求余

一开始是的想法是用减法代替除法,一直减到被减数小于减数,所得的被减数就是余数.为了方便编程,还在减法中对齐了被减数和减数的位数.但过程还是比较麻烦,会超时. 1 #include "stdafx.h" 2 #include<string> 3 #include<iostream> 4 using namespace std; 5 int b; 6 string decrease(string p, string cut) 7 { 8 int diff=p.siz

大数求余简单办法(水)

Prepared for New Acmer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7477    Accepted Submission(s): 2826 Problem Description 集训进行了将近2个礼拜,这段时间以恢复性训练为主,我一直在密切关注大家的训练情况,目前为止,对大家的表现相当满意,首先是绝大部分队员

Large Division (大数求余)

Given two integers, a and b, you should check whether a is divisible by b or not. We know that an integer a is divisible by an integer b if and only if there exists an integer c such that a = b * c. Input Input starts with an integer T (≤ 525), denot

如何运用同余定理求余数【hdoj 1212 Big Number【大数求余数】】

Big Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5930    Accepted Submission(s): 4146 Problem Description As we know, Big Number is always troublesome. But it's really important in our

java学习日记-基础-随机数组的求余运算

时间是2017年5月6日,青年节刚过,坐标上海,沪漂2个月. 就这样简短地开始吧.                                by:slowcity [案例分析1] 要求定义一个int 型数组a,包含100 个元素,保存100个随机的4 位数.再定义一个int 型数组b,包含10 个元素.统计a 数组中的元素对10 求余等于0 的个数,保存到 b[0]中:对10 求余等于1 的个数,保存到b[1]中,--依此类推 一般看到这类的最基本的思路:1先建立一个含数组存随机四位数 2