1. 程式人生 > >資訊學奧賽一本通(C++版) 第二部分 基礎演算法 第一章 高精度計算

資訊學奧賽一本通(C++版) 第二部分 基礎演算法 第一章 高精度計算

//1307 【例1.3】高精度乘法
//手動模擬乘法運算
//提交,測試點5,答案錯誤,猜測,應該是0的情況,沒考慮
//提供一組測試資料
//輸入:
//123
//0
//輸出:
//0
//考慮了0的情況,修改,提交AC 2017-11-9
//編到這裡,感覺高精度加是高精度演算法的基礎
#include <stdio.h>
#include <string.h>
int a[110],b[110],c[220];
char s[110];
void mul(){
    int i,j;
    for(i=1;i<=a[0];i++)
        for(j=1;j<=b[0];j++){
            c[i+j-1]+=a[i]*b[j];
            c[i+j]+=c[i+j-1]/10;
            c[i+j-1]%=10;
        }
    c[0]=a[0]+b[0]-1;
    if(c[c[0]+1]>0)c[0]+=1;
}
int main(){
    int i,len,k;
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(c,0,sizeof(c));
    scanf("%s",s);
    len=strlen(s),k=0;
    for(i=len-1;i>=0;i--)a[++k]=s[i]-'0';
    a[0]=len;
    
    scanf("%s",s);
    len=strlen(s),k=0;
    for(i=len-1;i>=0;i--)b[++k]=s[i]-'0';
    b[0]=len;
    
    if((a[0]==1&&a[1]==0)||(b[0]==1&&b[1]==0))printf("0");
    else{
        mul();
        for(i=c[0];i>=1;i--)printf("%d",c[i]);
    }
    return 0;
}

//1308 【例1.5】高精除
//基本可以猜到測試資料
//1 分子為0 商為0,餘數為0
//2 分子 分母相等,商為1,餘數為0
//3 在long long 範圍內的分子 分母
//以上三點至少可得30分
//如果是比賽,上述觀點能得部分分
//基本想法是用高精度減,但容易超時
//換思路,
//此文程式碼寫得比較短https://www.cnblogs.com/shenben/p/5878072.html
//學習
//演算法明白後,編寫程式碼,但除錯了70分鐘,樣例通過後,提交 2017-11-10
//提交,測試點3,答案錯誤
//提供一組測試樣例
//輸入:
//1000
//1
//輸出:
//1000
//0
//此題編寫,感覺自個程式碼在到處打補丁,很不順暢。
//修改,提交AC,不過,呢,程式碼全程都是自個編下來的,在編寫過程中再也沒有參考其他,也算是進步吧。
//日後此題應該還會再編寫一遍。
#include <stdio.h>
#include <string.h>
int a[310],b[310],c[310],d[310],t[310];//d商 t臨時陣列
char s[310];
int compare(int a[],int b[]){//a>b 1 a==b 0 a<b -1 高精度 比較大小
    int i;
    if(a[0]>b[0])return 1;
    if(a[0]<b[0])return -1;
    if(a[0]==b[0])
        for(i=a[0];i>=1;i--)
            if(a[i]>b[i])return 1;
            else if(a[i]<b[i])return -1;
    return 0;
}
void sub(int a[],int b[]){//a>b 高精度減
    int i;
    for(i=1;i<=b[0];i++){
        if(a[i]<b[i]){//借位
            a[i]+=10;
            a[i+1]--;
        }
        a[i]-=b[i];
    }
    i=a[0];
    while(a[i]==0)i--;
    if(i==0)a[0]=1;//此句寫成if(a[0]==0)a[0]=1;//漏了此句
    else  a[0]=i;    
}
int main(){
    int i,len,k,j,q;
    
    memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(d,0,sizeof(d));
    
    scanf("%s",s);
    len=strlen(s),k=0;
    for(i=len-1;i>=0;i--)a[++k]=s[i]-'0';
    a[0]=len;
    
    scanf("%s",s);
    len=strlen(s),k=0;
    for(i=len-1;i>=0;i--)b[++k]=s[i]-'0';
    b[0]=len;
    
    if(a[0]==1&&a[1]==0)printf("0\n0");//0初一其它數的處理
    else if(compare(a,b)==0)printf("1\n0");//a==b
    else if(compare(a,b)==-1){//a<b
        printf("0\n");
        for(i=a[0];i>=1;i--)printf("%d",a[i]);
    }else{//a>b
        d[0]=a[0]-b[0]+1,q=0;//商的位數
        for(i=a[0];i>=1;i--){
            if(compare(a,b)<=0)break;//此行寫成if(compare(a,b)==-1)break;//新增此行
            memset(t,0,sizeof(t)),t[0]=i,k=t[0];//此處寫成t[0]=a[0],//此處寫成k=0//漏了該句 t[0]=a[0];
            for(j=b[0];j>=1;j--)t[k]=b[j],k--;//此處寫成t[i+k]=b[j],k++;//此處寫成 for(j=b[0];j>=1;j--)t[i+k]=b[j],k++;
            while(compare(a,t)>=0)d[d[0]-q]++,sub(a,t);//此處寫成while(compare(a,t)==1)//此處寫成 while(compare(a,b)==1)
            q++;
        }
        i=d[0];
        while(d[i]==0)i--;//前導0的處理
        d[0]=i;
        for(i=d[0];i>=1;i--)printf("%d",d[i]);
        printf("\n");
        for(i=a[0];i>=1;i--)printf("%d",a[i]);
    }
    return 0;
}

//1309 【例1.6】迴文數(Noip1999)
//高精度加演算法,很有信心
//後判斷
//翻轉
//先加
//30步跳出
//仔細看題,發現並不只是十進位制,是N進位制,馬上意識到該題的難度了
//過了一晚之後,再想想,只要把十進位制中的10換成N,並編寫一個列印函式,列印位上的值大於等於10的 即可。
//題目沒有明確位數個數,故陣列均開到500
//樣例通過,提交,未通過,
//因是歷年NOIP普及組 複賽試題,容易得到測試資料
//看了看,確實會比較難過,因為輸入資料中就有16進位制
//馬上對讀取後的資料進行修改處理,題中沒有說輸入資料是否大寫,或是小寫,一併處理了
//再次提交,全未通過,檢視原始輸入輸出資料
//查了 洛谷 P1015 迴文數
//https://www.luogu.org/problemnew/show/1015
//洛谷上通過後,再進行提交,AC,
//http://ybt.ssoier.cn:8088中該題,沒法看,直接參考洛谷裡的題目,按裡面的輸入輸出要求進行提交
//2017-11-10
#include <stdio.h>
#include <string.h>
int N,a[500],b[500],step=0;
char s[500];
void add(int a[],int b[]){
    int i;
    for(i=1;i<=a[0];i++){
        a[i]+=b[i];
        a[i+1]+=a[i]/N;
        a[i]%=N;
    }
    if(a[a[0]+1]>0)a[0]+=1;
}
int judge(int a[]){//0非迴文,1迴文
    int i;
    for(i=1;i<=a[0]/2;i++)
        if(a[i]!=a[a[0]-i+1])
            return 0;
    return 1;
}
void overturn(int a[]){
    int i,j=0;
    b[0]=a[0];
    for(i=a[0];i>=1;i--)
        b[++j]=a[i];//此處寫成b[j]=a[i],j++;
}
void print(int a[]){
    int i;
    for(i=a[0];i>=1;i--)
        printf("%d",a[i]);
    printf("\n");
}
int main(){
    int len,i,k=0;
    scanf("%d%s",&N,s);
    len=strlen(s);
    for(i=len-1;i>=0;i--)//重寫讀入資料的處理
        if('0'<=s[i]&&s[i]<='9')
            a[++k]=s[i]-'0';
        else if('a'<=s[i]&&s[i]<='z')
            a[++k]=s[i]-'a'+10;
        else if('A'<=s[i]&&s[i]<='Z')
            a[++k]=s[i]-'A'+10;
    a[0]=len;
    while(judge(a)==0){
        //printf("1 "),print(a);
        overturn(a);
        //printf("2 "),print(b);
        add(a,b);
        //printf("3 "),print(a);
        step++;
        if(step==31)break;
    }
    
    if(step==31)printf("Impossible!");//此處寫成 printf("Impossible");
    else printf("STEP=%d",step);//此處寫成 printf("%d",step);
    return 0;
}