大数-精度问题(N的阶乘 mod P,C++ 大数相乘算法,ACM 1715 大菲波数)

N的阶乘 mod P

输入N和P(P为质数),求N! Mod P = ? (Mod 就是求模 %)
例如:n = 10, P = 11,10! = 3628800
3628800 % 11 = 10

Input
两个数N,P,中间用空格隔开。(N < 10000, P < 10^9)
Output输出N! mod P的结果。
Sample Input
10 11

Sample Output
10
运用公式:ab%p=(a%p)(b%p)%p
怎么推出来:(a+b)%m=(a%m+b%m)%m
我的问题:
我一开始想的是这跟分配律差不多,所以没有写外面的%p就写了两个%p,这是错的,为什么:因为你用括号里面求余想成完之后,万一还可以求余,那么就少求了一次,所以就错了。
例子; 3332%6=
错误的:33%6
32%6=32=6
正确的:(33%6
32%6)%6=6%6=0;
32*33=1056, 1056%6=0;
代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char** argv) {
 long long n,p;
 cin>>n>>p;
 long long sum=1;
 for(long long i=2;i<=n;i++){
  sum=(sum%p)*(i%p)%p;
 } 
 printf("%lld\n",sum) ;
 return 0;
}

C++ 大数相乘算法

首先说一下乘法计算的算法:同样是模拟人工计算时的方法。
从低位向高位乘,在竖式计算中,我们是将乘数第一位与被乘数的每一位相乘,记录结果之后,用第二位相乘,记录结果并且左移一位,以此类推,直到计算完最后一位,再将各项结果相加,得出最后结果。
1、先算1253,35得到15个1,32得到6个10,31得到3个100,下面是存储结果的数组的形式
在这里插入图片描述

2、接下来算1255,55得到25个10,25得到10个100,51得到5个1000;
在这里插入图片描述

3、乘法过程完毕。接下来从 a[0]开始向高位逐位处理进位问题。a[0]留下5,把1 加到a[1]上,a[1]变为32 后,应留下2,把3 加到a[2]上……最终使得a里的每个元素都是1 位数,结果就算出来了
结果就是6625。
在这里插入图片描述

总结一个规律:即一个数的第i 位和另一个数的第j 位相乘所得的数,一定是要累加到结果的第i+j 位上。这里i, j 都是从右往左,从0 开始数。

即:ans[i+j] = a[i]*b[j];

另外进位时要处理,当前的值加上进位的值再看本位数字是否又有进位;前导清零。
代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int x[1005],y[1005];
int xy[2010];
int main(int argc, char** argv) {
 string a1,a2;
 memset(x,0,sizeof(x));
 memset(y,0,sizeof(y));
 memset(xy,0,sizeof(xy));
 cin>>a1>>a2;
 int len1=a1.length();
 int len2=a2.length();
 for(int i=0;i<len1;i++){
  x[i]=a1[len1-1-i]-'0';
  //printf("%d",x[i]);
 }
 //printf("\n"); 
 for(int i=0;i<len2;i++){
  y[i]=a2[len2-1-i]-'0';
  //printf("%d",y[i]);
 }
 //printf("\n");
 for(int i=0;i<len1;i++){
  for(int j=0;j<len2;j++){
   xy[i+j]+=x[i]*y[j];
   
  }
 }
 for(int i=0;i<len1+len2;i++){
  if(xy[i]>9){
   xy[i+1]+=xy[i]/10;
   xy[i]=xy[i]%10;
  }
 } 
 int i;
 for(i=len1+len2;i>=0;i--){
  if(xy[i]==0){
   continue;
  }else{
   break;
  }
 }
 for(;i>=0;i--){
  printf("%d",xy[i]);
 }
 return 0;
}

ACM 1715 大菲波数

和上面的乘法类似,只不过换成了加法
因为是大数相加所以要开二位数组:int sum[1005][2010];
第一个是记录第几个数,第二个是记录进位的(十位,百位…)输出的时候记得去除前导0就行了。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int sum[1005][2010];
int main(int argc, char** argv) {
 int n;
 cin>>n;
 memset(sum,0,sizeof(sum));
 sum[1][0]=1;
 sum[2][0]=1;
 for(int i=3;i<=1000;i++){
  for(int j=0;j<2000;j++){
   sum[i][j]+=sum[i-1][j]+sum[i-2][j];
   if(sum[i][j]>9){
    sum[i][j+1]+=sum[i][j]/10;
    sum[i][j]=sum[i][j]%10; 
   }
  }
 }
 int y;
 while(n--){
  cin>>y;int i;
  for(i=1002;i>=0;i--) {
   if(sum[y][i]!=0){
    break;
   }
  }
  for(;i>=0;i--){
   cout<<sum[y][i];
  }
  cout<<endl;
 }
 return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值