从第一周开始我就有那么点因虚荣而后怕——这日志接不下去不悲剧了。果然,这一周题的难度飙升程度对于菜鸟我来说实在有点大。
第五题一点都不未雨绸缪的高精度运算。
算法到处都看得到,而且只是加减与正整数,所以说弱爆了啊!!!一点都不未雨绸缪搞得第七题重用就是水中月。但是开题之前在软院做得时候还是调了一天(可惜软院现在关闭了哇啊,悲催没有狠下心多做点当时,不过现在还是残留着题和讨论区~你懂的):
计算机所能完成的一个基本功能就是完成数据的计算,譬如加法、减法等等。但是在任何一种计算机上,计算中能够使用的数字都是有一定范围的,超过了范围,就没法得到精确的结果。
你现在接受了一个任务,要编写一个高精度计算器的核心部分。所谓高精度计算器,就是可以计算很大很大的数据的计算器。而你所需要编写的程序,就是真正完成高精度加法和高精度减法运算的两个函数,因为程序其它的部分已经由别人编写好了。
函数的输入、输出接口也已经定义完成,譬如 plus() 函数,它有三个参数 a、b 和 c,都是 char * 类型。a 和 b
分别是参加运算的两个整数,而 c 用来存放运算的结果。所有的数字都是以字符串的形式保存的。
注意,只需提交你自己编写的两个函数。
输入
输入的每一行是两个十进制的正整数和一个运算符,每个整数可以由最多 500 个数字组成。运算符可以是加号或者减号。
输出
对应着输入的每一行数据,输出计算的结果,每个结果占一行。
#include <stdio.h>
#include <string.h>
void plus(char *a, char *b, char *c);
void minus(char *a, char *b, char *c);
int main()
{
char
a[1000];
char
b[1000];
char
c[1000];
char
s[2];
while
(scanf("%s %s %s\n", a, s, b) == 3) {
if (s[0] == '+') {
plus(a, b, c);
} else if (s[0] == '-') {
minus(a, b, c);
}
printf("%s\n", c);
}
return
0;
}
void plus(char *a, char *b, char *c){
int i=0,j=0,k=0,max=0,min=0,temp=0;
char *pmax,*pmin;
memset(c,0,sizeof(c));
c[0]='0';
max=strlen(a);
min=strlen(b);
if (max<min){
pmax=b;
pmin=a;
temp=max;
max=min;
min=temp;
}
else{
pmax=a;
pmin=b;
}
for
(i=min-1,j=max-1,k=max;i>=0;i--,j--,k--)
c[k]=pmin[i]-'0'+pmax[j];
if(j>=0)
for
(;j>=0;j--,k--)
c[k]=pmax[j];
for
(i=max;i>=0;i--)
{
if
(c[i]>'9')
{
c[i]=c[i]-10;
c[i-1]++;
}
}
if (c[0]=='0'){
for
(i=1;i<=max;i++)
c[i-1]=c[i];
c[i-1]='\0';
}
else{
for
(i=0;i<=max;)
i++;
c[i]='\0';
}
for(i=0;i<strlen(c);i++){
if(c[i]!='0')
break;
max=strlen(c)-i;
}
if(c[0]=='0'){
for(j=0;j<max;j++,i++){
c[j]=c[i];
}
}
}
void minus(char *a, char *b, char *c){
int i,j,la,lb;
for(i=0;i<strlen(a);i++){
if(a[i]!='0')
break;
la=strlen(a)-i;
}
if(a[0]=='0'){
for(j=0;j<la;j++,i++){
a[j]=a[i];
}
}
for(i=0;i<strlen(b);i++){
if(b[i]!='0')
break;
la=strlen(b)-i;
}
if(b[0]=='0'){
for(j=0;j<la;j++,i++){
b[j]=b[i];
}
}
la=strlen(a);
lb=strlen(b);
if
(la>lb||(la==lb&&strcmp(a,b)>=0)){
for
(i=la-1,j=lb-1;j>=0;i--,j--)
a[i]=a[i]-(b[j]-'0');
for
(i=la-1;i>=0;i--)
if
(a[i]<'0'){
a[i]+=10;
a[i-1]--;
}
i=0;
while
(a[i]=='0')
i++;
if
(a[i]=='\0'){
c[0]='0';
c[1]='\0';
}
else{
for
(j=0;a[i]!='\0';i++,j++)
c[j]=a[i];
c[j]='\0';
}
}
else{
for
(i=la-1,j=lb-1;i>=0;i--,j--)
b[j]=b[j]-(a[i]-'0');
for
(j=lb-1;j>=0;j--)
if
(b[j]<'0'){
b[j]+=10;
b[j-1]--;
}
j=0;
while(b[j]=='0')
j++;
i=1;
c[0]='-';
for
(;b[j]!='\0';i++,j++)
c[i]=b[j];
c[i]='\0';
}
}
第六题
开始唬人的大整数因子
第一眼就感觉这题是要传说中得高精度除法么~从紧张到抓狂再到惆怅的过程差不多的时候才发现诶~小学老师貌似讲过一点整除技巧神马后三位数字相加能被3整除的数就能被三整除云云~果断百度出所有方法顿时山无棱天地合发现模拟题…,这里的问题就是7,于是采用了“若一个整数的个位数字截去,再从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除。如果差太大或心算不易看出是否7的倍数,就需要继续”的方法,不是最好,但也易行。
描述
已知正整数 k 满足 2<=k<=9,现给出长度最大为 30
位的十进制非负整数 c,求所有能整除 c 的 k。
输入
输入从文件 bignum.in
读取。若干个非负整数 c,c 的位数 <= 30。每行一个 c,当 c=-1
时中止(不要对-1进行计算!)
输出
请把结果保存到 bignum.out
中,每一个 c 的结果占一行。
1) 若存在满足 c % k == 0 的 k,输出所有这样的 k,中间用空格隔开,最后一个 k 后面有空格。
2) 若没有这样的 k 则输出 "none"。
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
void minus(char *a, char *b, char *c){
int i,j,la,lb;
la=strlen(a);
lb=strlen(b);
for
(i=la-1,j=lb-1;j>=0;i--,j--)
a[i]=a[i]-(b[j]-'0');
for (i=la-1;i>=0;i--)
if
(a[i]<'0'){
a[i]+=10;
a[i-1]--;
}i=0;
while (a[i]=='0')
i++;
if (a[i]=='\0'){
c[0]='0';
c[1]='\0';
}
else{
for
(j=0;a[i]!='\0';i++,j++)
c[j]=a[i];
c[j]='\0';
}
}
int main(){
int
len=0,length=0,i=0,j=0,total=0,la2,la3,flag6,ans=0;
char
c[50]="",k[50]="",rediv[50]="",bit[20]="",temp[50]="";
FILE *fp1,*fp2;
fp1=fopen("bignum.in","r");
fp2=fopen("bignum.out","w");
while(1){
fgets(c,50,fp1);
len=strlen(c)-1;
if(c[0]!='-')
{
i=0;total=0;flag6=0;
if((c[len-1]-'0')%2==0){
k[i]='2';
k[i+1]='
';
i+=2;
flag6++;
}
for(j=0;j<len;j++)
total+=(c[j]-'0');
if(total%3==0){
k[i]='3';
k[i+1]='
';
i+=2;
flag6++;
}
if(len>=2)
la2=(c[len-1]-'0')+10*(c[len-2]-'0');
else
la2=(c[len-1]-'0');
if(la2%4==0){
k[i]='4';k[i+1]='
';i+=2;
}
if((c[len-1]-'0')%5==0||(c[len-1]=='0')){
k[i]='5';k[i+1]='
';i+=2;
}
if(flag6==2){
k[i]='6';k[i+1]='
';i+=2;
}
length=len;
for(j=0;j<len;j++){
rediv[j]=c[j];
}
while(length>2){
for(j=0;j<length-1;j++){
temp[j]=rediv[j];
}
bit[1]=(rediv[length-1]-'0')*2+'0';
bit[0]=(rediv[length-1]-'0')*2/10+'0';
minus(temp,bit,rediv);
length=strlen(rediv);
memset(temp,0,sizeof(temp));
}
if(length==2)
ans=rediv[1]-'0'+(rediv[0]-'0')*10;
else
ans=rediv[0]-'0';
if(ans%7==0){
k[i]='7';k[i+1]='
';i+=2;
}
if(len>=3)
la3=(c[len-1]-'0')+10*(c[len-2]-'0')+100*(c[len-3]-'0');
else
if(len==2) la3=(c[1]-'0')+10*(c[0]-'0');
else
if(len==1) la3=(c[1]-'0');
if(la3%8==0){
k[i]='8';k[i+1]='
';i+=2;
}
if(total%9==0){
k[i]='9';k[i+1]='
';i+=2;
}
if(strlen(k)==0)
{fputs("none\n",fp2);continue;}
else
{k[i-1]='\n';
fputs(k,fp2);}
}
else
break;
memset(k,0,sizeof(k));
memset(c,0,sizeof(c));
memset(bit,0,sizeof(bit));
memset(rediv,0,sizeof(rediv));
memset(temp,0,sizeof(temp));
}
return 0;
}
第三题
十分纠结的波兰式
这题还真是从始至终都没思路~因为各路大神已经在我做题之前已经探路了…诶~说实话虽然自己也想了好久~但还是在无果之下抵不住大神的算法诱惑~果断递归走起~
但是最初最纠结的还是恨铁不成钢的加减高精度啊~
此处省略N个字~因为极度排斥为了正负号完全重写高精度,于是终于找到了偷懒法:
(a、b均为非负整数)加法有四种输入情况(中缀写法):
a + b ,-a+-b, -a + b,
a+-b,
第二种可以转化为-( a +
b)的加法,后两种可以分别化成b-a, a-b的减法~在加法的函数里判断下调用即可~而减法则可以如法炮制~甚至可以在-a - -b的时候调用减法自身变成b – a
的减法~。于是又在纠结递归参数传递问题,因为双目运算需要两个返回值,而前一个返回的数组名和后一个返回的相同就覆盖了~于是在判断进入每个运算后都设两个数组,各存一个,最后运算的结果一直存在从始至终的结果数组中,提交……哇!倒二。纠结良久询问斌神~果断得知还有输入-0直接输出0……判断完果断A啊哈。
背景
以下是几个标准的表达式:
- 5 * 2 +
-3
- 5 * (2 +
-3)
- 5 + ((-4
* -5) + (((5 + (6 - 2)) * 7 + ((4 + 2) * (3 - 1))))
与之等价的波兰表达式为
- + * 5 2
-3
- * 5 + 2
-3
- + 5 + *
-4 -5 + * + 5 - 6 2 7 * + 4 2 - 3 1
在普通的表达式中,符号是位于运算对象之间的,而在波兰表达式中,运算符号位于参与运算的对象之前。
波兰式在计算中的价值在于它不需要使用括号,之所以如此是由于波兰式的操作符的先后顺序是明确的。
如果我们用 P 表示波兰表达式,用
O 表示操作符,用
D
表示数字,则可以将波兰表达式定义为 P = O P P 或
P =
D。
任务
编写程序计算波兰表达式的值。
输入
输入第一行是一个整数,表示输入文件中共有几个波兰式,之后每一行是一个波兰表达式。
每个表达式包含数字和二元操作符 +、-、*,操作数和运算结果都在
[-101000, 101000] 之间。
可以假设每行的数据(运算符号和数字)总共不超过 100 个。
输入请从文件 polan.in
中读取。
输出
对每个表达式输出其值,并保存到 polan.out
中。
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
char * minus(char *b, char *a,char *temp);
char * movefore(char *ab){
int i=0,len=0;
len=strlen(ab);
for(i=0;i<len;i++){
ab[i]=ab[i+1];
}
return ab;
}
char * moveback(char *ab){
int i=0,len=0;
len=strlen(ab);
for(i=len;i>0;i--){
ab[i]=ab[i-1];
}
ab[0]='-';
return ab;
}
char * plus(char *b, char *a,char *temp){
int i=0,j=0,k=0,max=0,min=0;
char *pmax,*pmin;
if(*a=='-'&&*b!='-'){
return
minus(movefore(a),b,temp);
}
else
if(*a!='-'&&*b=='-'){
return
minus(movefore(b),a,temp);
}
max=strlen(a)>=strlen(b)?strlen(a):strlen(b);
min=strlen(a)<strlen(b)?strlen(a):strlen(b);
pmax=strlen(a)<strlen(b)?b:a;
pmin=strlen(a)<strlen(b)?a:b;
if(*a!='-'&&*b!='-'){
temp[0]='0';
for
(i=min-1,j=max-1,k=max;i>=0;i--,j--,k--)
temp[k]=pmin[i]-'0'+pmax[j];
if(j>=0)
for
(;j>=0;j--,k--)
temp[k]=pmax[j];
for
(i=max;i>=0;i--){
if
(temp[i]>'9')
{
temp[i]=temp[i]-10;
temp[i-1]++;
}
}
if
(temp[0]=='0'){
for
(i=1;i<=max;i++)
temp[i-1]=temp[i];
temp[i-1]='\0';
}
else{
for
(i=0;i<=max;)
i++;
temp[i]='\0';
}
return
temp;
}
else
if(*a=='-'&&*b=='-'){
temp[0]='-';
temp[1]='0';
for
(i=min-1,j=max-1,k=max;i>0;i--,j--,k--)
temp[k]=pmin[i]-'0'+pmax[j];
if(j>0){
for
(;j>0;j--,k--)
temp[k]=pmax[j];
}
for
(i=max;i>1;i--){
if
(temp[i]>'9'){
temp[i]=temp[i]-10;
temp[i-1]++;
}
}
if
(temp[1]=='0'){
for
(i=2;i<=max;i++)
temp[i-1]=temp[i];
temp[i-1]='\0';
}
//temp[max+1]='\0';
if((strlen(temp)==2)&&(temp[1]=='0')){
temp[0]='0';temp[1]='\0';
}
return temp;
}
}
char * minus(char *b, char *a,char *temp){
int i,j,la,lb;
if(*a=='-'&&*b!='-'){
return
plus(moveback(b),a,temp);
}
else
if(*a!='-'&&*b=='-'){
return
plus(movefore(b),a,temp);
}
else
if(*a=='-'&&*b=='-'){
return
minus(movefore(a),movefore(b),temp);
}
else
if(*a!='-'&&*b!='-'){
la=strlen(a);
lb=strlen(b);
if
(la>lb||(la==lb&&strcmp(a,b)>=0)){
for
(i=la-1,j=lb-1;j>=0;i--,j--)
a[i]=a[i]-(b[j]-'0');
for
(i=la-1;i>=0;i--)
if
(a[i]<'0'){
a[i]+=10;
a[i-1]--;
}i=0;
while
(a[i]=='0')
i++;
if
(a[i]=='\0'){
temp[0]='0';
temp[1]='\0';
}
else{
for
(j=0;a[i]!='\0';i++,j++)
temp[j]=a[i];
temp[j]='\0';
}
}
else
if(strlen(b)==2&&*(b+1)=='0'){
temp[0]='0';temp[1]='\0';
}
else{
for
(i=la-1,j=lb-1;i>=0;i--,j--)
b[j]=b[j]-(a[i]-'0');
for
(j=lb-1;j>=0;j--)
if
(b[j]<'0'){
b[j]+=10;
b[j-1]--;
}
j=0;
while(b[j]=='0')
j++;
temp[0]='-';
for
(i=1;b[j]!='\0';i++,j++)
temp[i]=b[j];
temp[i]='\0';
}
return temp;
}
}
char *mul(char *sa,char *sb,char *temp){
int la=0,lb=0,max=0,pmax=0,i=0,j=0,pm=0;
char stemp[3000]="";
if(*sa=='0'||*sb=='0'||(*(sa+1)=='0'&&*sa=='-')||(*(sb+1)=='0'&&*sb=='-')){
temp[0]='0';
}
else{
la = strlen(sa);
lb = strlen(sb);
pm=pmax=max=2*(la>lb?la:lb);
for(i=la-1;i>=0;i--){
for(j=lb-1;j>=0;j--){
if(sa[i]!='-'&&sb[j]!='-'){
stemp[pmax-1]+=(sa[i]-'0')*(sb[j]-'0');
if(stemp[pmax-1]>9){
stemp[pmax-2]+=stemp[pmax-1]/10;
stemp[pmax-1]%=10;
}pmax--;
}
}
pm--;
pmax=pm;
}
for(pmax=0;pmax<max;pmax++){
if(stemp[pmax]!='\0')
break;
}
if((*sa!='-'&&*sb!='-')||(*sa=='-'&&*sb=='-')){
for(i=0;pmax<max;i++,pmax++){
temp[i]=stemp[pmax]+'0';
}temp[i]='\0';
}
else{
for(i=1;pmax<max;i++,pmax++){
temp[i]=stemp[pmax]+'0';
}
temp[0]='-';
}
}
return temp;
}
char *get(char * str){
scanf("%s",str);
if(strlen(str)==2&&str[1]=='0'&&str[0]=='-'){
str[0]='0';str[1]='\0';
return str;
}
else
if((str[0]=='+'||str[0]=='-'||str[0]=='*')&&strlen(str)==1){
if(str[0]=='+'){
char
s1[10000]="",s2[10000]="";
return
plus(get(s1),get(s2),str);
}
if(str[0]=='-'){
char
s1[10000]="",s2[10000]="";
return
minus(get(s1),get(s2),str);
}
if(str[0]=='*'){
char
s1[10000]="",s2[10000]="";
return
mul(get(s1),get(s2),str);
}
}
else
return str;
}
int main(){
int times=0,n=0;
FILE *fp1,*fp2;
char t[10000]="";
fp1=freopen("polan.in","r",stdin);
fp2=freopen("polan.out","w",stdout);
scanf("%d",×);
for(n=0;n<times;n++){
puts(get(t));
memset(t,'\0',sizeof(t));
}
return 0;
}
第四题 RP至上的斐波那契
又是一题大神铺路的题~于是照着把1~1000位的所有斐波那契全部存起~到时查询使用的大众式方法,交上~哇了最后两个…纠结良久~琛神路过~几秒看出最初读取一行目标数列的数组太抠门了,只开了1001~改完果断……只剩最后一个WA…于是从不甘不愿到泪流满面四出乱改~也不知如何就在那绝望的边缘随意一交~RP就这样爆发了~:
Fibonacci 数列有如下特点:其第 1 , 2
项均为 1 , 1 。从第 3 个数开始,该数是其前两个数之和 . 即 :
- F1=1 (n=1)
- F2=1 (n=2)
- Fn=Fn-1+Fn-2 (n>=3)
请你编写一个函数 fun ,它的功能是:对于一个给定的 数( N ), 求不大于 N 的最大 Fibonacci 数。
输入
输入从 fibo.in 中读取,它的第一行是一个正整数,表示下面有几组数据需要计算。之后的每一行是一个数据 N ,其中 1
=< N <= 101000
。
输出
对应输入的每一行,输出一个不大于 N 的最大 Fibonacci 数,并把结果保存到 fibo.out 中。
char fib[5000][1100];
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
void plus(char *a, char *b, char *c){
int i=0,j=0,k=0,max=0,min=0;
char *pmax,*pmin;
max=strlen(b);
min=strlen(a);
pmax=b;
pmin=a;
if((max==min)&&(*a+*b-'0'>='9')){
*c='0';
for
(i=min-1,j=max-1,k=max;i>=0;i--,j--,k--)
*(c+k)=pmin[i]-'0'+pmax[j];
if(j>=0)
for
(;j>=0;j--,k--)
*(c+k)=pmax[j];
for
(i=max;i>=0;i--){
if
(*(c+i)>'9'){
*(c+i)=*(c+i)-10;
*(c+i-1)+=1;
}
}
if(*c=='0'){
for(i=1;i<=max;i++)
*(c+i-1)=*(c+i);
*(c+i-1)='\0';
}
else
*(c+max+1)='\0';
}
else{
for
(i=min-1,j=max-1,k=max-1;i>=0;i--,j--,k--)
*(c+k)=pmin[i]-'0'+pmax[j];
if(j>=0)
for
(;j>=0;j--,k--)
*(c+k)=pmax[j];
for
(i=max;i>=0;i--){
if
(*(c+i)>'9'){
*(c+i)=*(c+i)-10;
*(c+i-1)+=1;
}
}*(c+max)='\0';
}
}
int main(){
int
count=0,times=0,i=0,j=0,t=0,flag=0,len=0,length=0;
char *F1,*F2,*Fn,aim[1100]="";
memset(fib,'\0',sizeof(fib));
FILE *fp1,*fp2;
fp1=freopen("fibo.in","r",stdin);
fp2=freopen("fibo.out","w",stdout);
fib[0][0]='1';fib[1][0]='1';
F1=&fib[0][0];F2=&fib[1][0];
Fn=&fib[2][0];
for(count=0;count<=4980;++count){
plus(F1,F2,Fn);
F1=F2;
F2=Fn;
Fn+=1100;
}
scanf("%d",×);
for(count=0;count<times;++count){
scanf("%s",aim);
length=strlen(aim);
for(i=0;i<4980;i++){
len=strlen(fib[i]);
if(len>=length-1)
break;
}
flag=0;
for(t=0;t<20;t++,i++){
len=strlen(fib[i]);
if(len==length){
for(j=0;j<len;j++){
if(fib[i][j]>aim[j]){
flag=1;
break;
}
else
if(fib[i][j]<aim[j])
break;
}
}
if(flag==1){
puts(fib[i-1]);
break;
}
if(len>length){
puts(fib[i-1]);
break;
}
}
}
return 0;
}
————————————————亚历山大而扁扁的分割线————————————
这一周感触最深的就是能码出自己思想的代码才是最幸福的,虽然现在是在打基础,想得也是前人想过的,可能最后绞尽脑汁也想不出来,但是真的要在最初的时候自己想思路,实在不行再借鉴神牛的,万一(似乎一点信心都没)想出来了,真是要比码别人思想的代码要有成就的多啊。
诶~众里寻wa千百度,蓦然回首,那A却在保密最深处。