/* ID: linjd821 LANG: C++ TASK: 高精度模板 */ //高精度模板,注意本模板并没有考虑中间会出现负数的情况 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <assert.h> #include <ctype.h> #include <map> #include <string> #include <set> #include <bitset> #include <utility> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <iostream> #include <fstream> #include <list> using namespace std; const int MAXL = 500; struct BigNum { int num[MAXL]; int len; }; //高精度比较 a > b return 1, a == b return 0; a < b return -1; int Comp(BigNum &a, BigNum &b) { int i; if(a.len != b.len) return (a.len > b.len) ? 1 : -1; for(i = a.len-1; i >= 0; i--) if(a.num[i] != b.num[i]) return (a.num[i] > b.num[i]) ? 1 : -1; return 0; } //高精度加法 BigNum Add(BigNum &a, BigNum &b) { BigNum c; int i, len; len = (a.len > b.len) ? a.len : b.len; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < len; i++) { c.num[i] += (a.num[i]+b.num[i]); if(c.num[i] >= 10) { c.num[i+1]++; c.num[i] -= 10; } } if(c.num[len]) len++; c.len = len; return c; } //高精度减法,保证a >= b BigNum Sub(BigNum &a, BigNum &b) { BigNum c; int i, len; len = (a.len > b.len) ? a.len : b.len; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < len; i++) { c.num[i] += (a.num[i]-b.num[i]); if(c.num[i] < 0) { c.num[i] += 10; c.num[i+1]--; } } while(c.num[len] == 0 && len > 1) len--; c.len = len; return c; } //高精度乘以低精度,当b很大时可能会发生溢出int范围,具体情况具体分析 //如果b很大可以考虑把b看成高精度 BigNum Mul1(BigNum &a, int &b) { BigNum c; int i, len; len = a.len; memset(c.num, 0, sizeof(c.num)); //乘以0,直接返回0 if(b == 0) { c.len = 1; return c; } for(i = 0; i < len; i++) { c.num[i] += (a.num[i]*b); if(c.num[i] >= 10) { c.num[i+1] = c.num[i]/10; c.num[i] %= 10; } } while(c.num[len] > 0) { c.num[len+1] = c.num[len]/10; c.num[len++] %= 10; } c.len = len; return c; } //高精度乘以高精度,注意要及时进位,否则肯能会引起溢出,但这样会增加算法的复杂度, //如果确定不会发生溢出, 可以将里面的while改成if BigNum Mul2(BigNum &a, BigNum &b) { int i, j, len = 0; BigNum c; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < a.len; i++) for(j = 0; j < b.len; j++) { c.num[i+j] += (a.num[i]*b.num[j]); if(c.num[i+j] >= 10) { c.num[i+j+1] += c.num[i+j]/10; c.num[i+j] %= 10; } } len = a.len+b.len-1; while(c.num[len-1] == 0 && len > 1) len--; if(c.num[len]) len++; c.len = len; return c; } //高精度除以低精度,除的结果为c, 余数为f void Div1(BigNum &a, int &b, BigNum &c, int &f) { int i, len = a.len; memset(c.num, 0, sizeof(c.num)); f = 0; for(i = a.len-1; i >= 0; i--) { f = f*10+a.num[i]; c.num[i] = f/b; f %= b; } while(len > 1 && c.num[len-1] == 0) len--; c.len = len; } //高精度*10 void Mul10(BigNum &a) { int i, len = a.len; for(i = len; i >= 1; i--) a.num[i] = a.num[i-1]; a.num[i] = 0; len++; //if a == 0 while(len > 1 && a.num[len-1] == 0) len--; } //高精度除以高精度,除的结果为c,余数为f void Div2(BigNum &a, BigNum &b, BigNum &c, BigNum &f) { int i, len = a.len; memset(c.num, 0, sizeof(c.num)); memset(f.num, 0, sizeof(f.num)); f.len = 1; for(i = len-1;i >= 0;i--) { Mul10(f); //余数每次乘10 f.num[0] = a.num[i]; //然后余数加上下一位 ///利用减法替换除法 while(Comp(f, b) >= 0) { f = Sub(f, b); c.num[i]++; } } while(len > 1 && c.num[len-1] == 0)len--; c.len = len; } void print(BigNum &a) { int i; for(i = a.len-1; i >= 0; i--) printf("%d", a.num[i]); puts(""); } //将字符串转为大数存在BigNum结构体里面 BigNum ToNum(char *s) { int i, j; BigNum a; a.len = strlen(s); for(i = 0, j = a.len-1; s[i] != '/0'; i++, j--) a.num[i] = s[j]-'0'; return a; } void Init(BigNum &a, char *s, int &tag) { int i = 0, j = strlen(s); if(s[0] == '-') {j--; i++; tag *= -1;} a.len = j; for(; s[i] != '/0'; i++, j--) a.num[j-1] = s[i]-'0'; //print(a); } int main() { BigNum a, b; char s1[100], s2[100]; while(scanf("%s %s", s1, s2) != EOF) { int tag = 1; Init(a, s1, tag); Init(b, s2, tag); a = Mul2(a, b); if(a.len == 1 && a.num[0] == 0) { puts("0"); } else { if(tag < 0) putchar('-'); print(a); } } return 0; } /* sum[]数组是存最后的结果的。s[]是要加的数,有几个数相加,就调用几次, 在使用之前,sum[]要清零,sum[0]是最低位。 */ //zstu 1022 void plus(int sum[],char s[]) { int i,len,j,k; for(j=0,i=strlen(s)-1;i>=0;i--,j++) { sum[j]+=s[i]-'0'; k=j; while(sum[k]>9) { sum[k+1]+=sum[k]/10; sum[k]%=10; } } } /*pku Division 给三个正整数a,b,t求出(t^a-1)/(t^b-1) 如果不是整数或这个整数不小于100位,就输出 is not an integer with less than 100 digits. 如果t=1,那么就不是整数了(因为没有意义)。 当t!=1首先判断是否为整数,可以这么想,如果是整数那么 (t^b-1)|(t^a-1) 也就是gcd(t^b-1,t^a-1)=t^b-1; 又因为gcd(f(a),f(b))=f(gcd(a,b)); (在这里f(x)=t^x-1); 那么a%b=0 所以当a%b!=0时就直接输出答案了。 判断长度可以先取一下对数。 如果在100以内就做下去,(我取了105位,保守一点) 接下来就要计算了,如果直接算会TLE的, 先化简单一下公式 这里有一个公式 x^n-1=(x-1)*(1+x+x^2+x^3+...+x^(n-1)) 因为a%b==0; 所以可以令x=t^b 那么(t^a-1)/(t^b-1)=1+x+x^2+x^3+...+x^(a/b-1) 接下来就可以二分做了。 二分可以递归,也可以用循环。 构造矩阵 [x,1] [0,1] 因为 [x,1]*[x,1]=[x^2,x+1] [0,1] [0,1] [ 0 , 1 ] [x,1]^n=[x^n,1+x+x^2+...+x^n-1] [0,1] [ 0 , 1 ] 所以只要将这个矩阵乘n+1次就可以算出1+x+x^2+x^3+...+x^n 下面是代码,还要注意数组要开大一点,我开了100,re了 开了500才过的 */ #include<stdio.h> #include<string.h> #include<math.h> struct BigNum { int num[410]; int len; }sum[2][2],temp[2][2]; struct BigNum pb,tmp; void multinum(struct BigNum &a,struct BigNum b) { int i,j; struct BigNum c; memset(c.num,0,sizeof(c.num)); for(i=0;i<a.len;i++) { for(j=0;j<b.len;j++) { c.num[i+j]+=a.num[i]*b.num[j]; if(c.num[i+j]>9) { c.num[i+j+1]+=c.num[i+j]/10; c.num[i+j]%=10; } } } c.len=a.len+b.len; if(c.num[a.len+b.len-1]==0) c.len--;; a=c; } int find(int a[]) { int i; for(i=409;i>=0&&a[i]==0;i--); if(i<0) return 1; return i+1; } void plus(struct BigNum &a,struct BigNum b) { int i; for(i=0;i<b.len;i++) a.num[i]+=b.num[i]; for(i=0;i<408;i++) { if(a.num[i]>9) { a.num[i+1]+=a.num[i]/10; a.num[i]%=10; } } a.len=find(a.num); } void multimatrix(struct BigNum sum[][2],struct BigNum temp[][2]) { int i,j,k; struct BigNum c[2][2],a; for(i=0;i<2;i++) for(j=0;j<2;j++) { memset(c[i][j].num,0,sizeof(c[i][j].num)); c[i][j].len=1; } for(i=0;i<2;i++) { for(j=0;j<2;j++) { for(k=0;k<2;k++) { a=sum[i][k]; multinum(a,temp[k][j]); plus(c[i][j],a); } } } for(i=0;i<2;i++) for(j=0;j<2;j++) sum[i][j]=c[i][j]; } int main() { int i,t,a,b,j,k,u; __int64 lena,lenb; while(scanf("%d%d%d",&t,&a,&b)!=EOF) { printf("(%d^%d-1)/(%d^%d-1) ",t,a,t,b); if(a%b||t==1) { printf("is not an integer with less than 100 digits./n"); continue; } if(a==b) { puts("1"); continue; } lena=a*log10(t)+1; lenb=b*log10(t); if(lena-lenb>104||lenb>104) { printf("is not an integer with less than 100 digits./n"); continue; } memset(pb.num,0,sizeof(pb.num)); pb.num[0]=1; pb.len=1; memset(tmp.num,0,sizeof(tmp.num)); j=t; for(i=0;j;i++) { tmp.num[i]=j%10; j/=10; } if(i==0) tmp.len=1; else tmp.len=i; j=b; while(j) { if(j%2) multinum(pb,tmp); multinum(tmp,tmp); j>>=1; } j=a/b; memset(tmp.num,0,sizeof(tmp.num)); tmp.num[0]=1; tmp.len=1; temp[0][1]=temp[1][1]=sum[0][0]=sum[1][1]=tmp; tmp.num[0]=0; temp[1][0]=sum[0][1]=sum[1][0]=tmp; temp[0][0]=pb; while(j) { if(sum[0][1].len>=100) break; if(j%2) multimatrix(sum,temp); j>>=1; multimatrix(temp,temp); } if(sum[0][1].len>=100) { printf("is not an integer with less than 100 digits./n"); continue; } for(j=sum[0][1].len-1;j>=0;j--) printf("%d",sum[0][1].num[j]); puts(""); } return 0; }