POJ2635 The Embarrassed Cryptographer (同余)

题目大意:给出一个大数K<=10^180,再给出一个数L<=10^6;K是由2个素数相乘得来的,如果K的任一个素数小于L则输出bad 和小于L的这个素数,或者2个因子都小于L的时候输出最小的因子。

思路:大数取余。为了避免TIE使用了1000进制。因为只是一次运算所以不必逆置数组。说实在的,10进制想不通为什么会TIE啊~~囧~~求大牛指教啊~~现在的计算机1s不是已经能处理10^8的执行次数了吗?10进制一个100W的素数就只是n*logn的算法就只是2*10^7次执行次数嘛~~下面的枚举素数的时候,n*m的算法嘛~~100w内的素数个数只有78498个嘛~~就10^5嘛~~即n为10^5嘛~~m就是大数的数位啊~~最多180嘛~~不就是总共10^7执行次数嘛~~所以在2s内竟然无限TIE我真的想不通~~~囧。。

大数取模用到了关键定理:(来自小优博客)

高精度求模。

主要利用Kt数组和同余模定理。

例如要验证123是否被3整除,只需求模124%3

但当123是一个大数时,就不能直接求,只能通过同余模定理对大数“分块”间接求模

具体做法是:

先求1%3 = 1

再求(1*10+2)%3 = 0

再求 (0*10+4)% 3 = 1

那么就间接得到124%3=1,这是显然正确的

而且不难发现, (1*10+2)*10+4 = 124

这是在10进制下的做法,千进制也同理,*10改为*1000就可以了

 


program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std; 
char mm[200];
int tmp[200]; 
int tt[50][2];
int prime[100000];
int flag[1000010]; //这个数组大小坑死我,晕。WA了2次 
int pp;
int prk,k;
int start1,start2; 
int get_remainder(int p)
{
   
   int rr,bb=1000; 
   for(int i=0;i<start2;i++)//老是出现++的问题 
   {
      
      if(i==0)
      {
         rr=tt[i][0]%p;//先计算数组下标第一项
                        
      }
      else
         {
                                      
           rr=(rr*1000+tt[i][0])%p; //后面的就可以由前面的推出来了
         }
      //cout<<"i tt[i][0]  rr  "<<i<<' '<<tt[i][0]<<' '<<rr<<endl;   
      //system("pause");        
    }
    
   if(rr==0) return 0;
   return 1; 
        
} 
int main()
{
prk=0; 
for(__int64 i=2;i<1000010;i++)
{
   if(!flag[i])
   {
    prime[prk++]=i;
    for(__int64 g=i*i;g<1000010;g+=i)//以后还是用2 个64int好了。
       flag[g]=1;               
   }        
}
//cout<<prime[prk-1]<<endl;
//cout<<prime[prk-2]<<endl;
//cout<<prk<<endl; 
while(scanf("%s%d",mm,&pp)!=EOF)
{
  if(mm[0]=='0'&&pp==0)break; 
  int len=strlen(mm);
  for(int i=0;i<len;i++)
  {
     tmp[i]=mm[i]-'0';       
  } 
  int cur=len%3;
  int tmppp=0; 
  if(cur!=0)                   //提前把前面不为3的整数倍的部分提取出来
     {  
        
        for(int i=0;i<cur;i++)
             tmppp=tmppp*10+tmp[i];
        tt[0][0]=tmppp;     
     } 
  start1=0,start2=0; 
  if(cur!=0){  start1=cur;  start2=1;}  
  int tmt=1;
  tmppp=0; 
  for(int i=start1;i<len;i++)//把转换成1000进制的数放到2维数组里面
  {
     tmppp=tmppp*10+tmp[i]; 
     if(tmt==3)
     {
       tt[start2++][0]=tmppp;
        
       tmppp=0;
       tmt=1;        
     }
     else tmt++;      
  }

  //for(int i=0;i<start2;i++)/ 
    //  cout<<tt[i][0]<<' '<<endl;
  int i=0; 
  for(;i<prk && prime[i]<=pp;i++)//枚举
  { 
    //cout<<"prime[i]  "<<prime[i]<<' '<<endl;
    if(get_remainder(prime[i])==0)
       break;        
  } 
         
  if(prime[i]<pp)/// 
       printf("BAD %d\n",prime[i]) ;
  else if(prime[i]==pp || prime[i]>pp)
       printf("GOOD\n") ;  
                
     
                                    
}
system("pause"); 
return 0;} 


 

小优的博客说的很详细:http://blog.csdn.net/lyy289065406/article/details/6648530

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值