#include #include #include #define TRIANGLE(x,y)  triangle[(x)*L+(y)] #define F(x,y)         fun[(x)*L+(y)] void PolyMul(mpz_t *src1, mpz_t *src2, mpz_t *dst, int L, mpz_t mod) {     int i,j;mpz_t tmp,tmpp;     mpz_init(tmp);mpz_init(tmpp);     for(i=0;i=1;i--){  mpz_add(tmp1,result,F(s,i));  mpz_mul(tmp2,tmp1,t4);  mpz_mod(result,tmp2,five_L);     }     mpz_add(tmp1,result,F(s,0));     mpz_mod(result,tmp1,five_L);     mpz_clear(tmp1);mpz_clear(tmp2); } void Get_Mult_No_5(mpz_t N,   int L,   mpz_t *fun,   mpz_t five_L,   mpz_t *five_i,   mpz_t result) {     mpz_t t1,t2,t3,t4;     int i;     mpz_init(t1);mpz_init(t2);mpz_init(t3);mpz_init(t4);     mpz_fdiv_qr(t1,t2,N,five_L);     i=mpz_tstbit(t1,0);//If odd, multiply result by -1, otherwise 1     if(i){//odd  mpz_sub_ui(result,five_L,1);     }else{  mpz_set_ui(result,1);     }     mpz_set_ui(t4,0);     for(i=L-1;i>=0;i--){  int r,s;  mpz_fdiv_qr(t1,t3,t2,five_i[i]);  mpz_set(t2,t3);  //Assert t1 is from 0 to 4  if(mpz_cmp_ui(t1,5)>=0){      fprintf(stderr,"Data error i=%d/n",i);      exit(-1);  }  r=mpz_get_ui(t1);  mpz_mul_ui(t4,t4,5);  if(i>0){    for(s=0;s1)        mpz_set_ui(F(1,1),50*5);     if(L>2)        mpz_set_ui(F(1,2),35*5*5);     if(L>3)        mpz_set_ui(F(1,3),10*5*5*5);     if(L>4)        mpz_set_ui(F(1,4),1*5*5*5*5);     for(i=0;i<=4;i++)mpz_mod(F(1,i),F(1,i),fiveL);     for(i=5;i0     mpz_add_ui(tmp,F(L-1,0),1);     if(mpz_cmp(tmp,fiveL)!=0){  for(i=0;i0){  Get_Mult_No_5(N,L,fun,fiveL,tmp1,tmp);  mpz_mul(tmpp,m5L,tmp);  mpz_mod(m5L,tmpp,fiveL);  mpz_fdiv_q_ui(N,N,5);  mpz_add(count_5,count_5,N);     }     for(i=0;i0){i/=5;count5+=i;}     for(i=1;i<=N;i++){  int j=i;  while(j%5==0)j/=5;  while(count5>0&&j%2==0){j/=2;count5--;}  mpz_mul_ui(result,result,j);  mpz_mod(result,result,tenL);     }     mpz_out_str(stdout,10,result);     printf("/n"); } void calc(mpz_t N, int L){      int smallN=L*4;      mpz_t m5L;      mpz_t two,twomL;      mpz_t fiveL;      mpz_t result;      mpz_t count_5;      if(mpz_cmp_ui(N,smallN)<0){   short_calc(mpz_get_ui(N),L);   return;      }      mpz_init(count_5);      mpz_init(m5L);      mpz_init(fiveL);      mpz_set_ui(m5L,5);      mpz_pow_ui(fiveL, m5L, L);//fiveL=5^L      Get_m5L(N,L,m5L,fiveL,count_5);  //m5L = final_result % (5^L)      mpz_add_ui(count_5,count_5,L);      mpz_init(two);      mpz_init(twomL);      mpz_set_ui(two,2);      mpz_add_ui(twomL,fiveL,1);      mpz_fdiv_q_ui(twomL,twomL,2);      mpz_powm(twomL,twomL,count_5,fiveL);// (twomL = 2^(-L) mod (5^L))      mpz_init(result);      mpz_mul(result,twomL,m5L);         mpz_mod(twomL,result, fiveL); //twomL = (m5L*2^(-L)) %(5^L)      mpz_pow_ui(m5L,two,L); //m5L= 2^L      mpz_mul(result,twomL, m5L); //2^L * (m5L*2^(-L))%(5^L), the final result      mpz_out_str(stdout,10,result);      printf("/n");      mpz_clear(result);      mpz_clear(twomL);      mpz_clear(two);      mpz_clear(fiveL);      mpz_clear(m5L); } int main(void) {     mpz_t N;     int L;     size_t len;     mpz_init(N);     printf("Please input large number N, so that we could process for N!/n");     len=mpz_inp_str(N,stdin,10);     if(len>1024){      printf("Current only process number whose length no more than 1000/n");      return -1;     }     printf("Please input number of digits to get (no more than 100):");     scanf("%d",&L);     if(L>100){     printf("Input Out of range/n");     return -1;     }     if(L<3)L=3;     printf("Calcuate last %d non-zero digits of ",L);     mpz_out_str(stdout,10,N);     printf("/n");     calc(N,L);     mpz_clear(N);     return 0; }