5920 Ugly Problem 大數減法模擬+貪心
阿新 • • 發佈:2018-12-10
1.題意:給你一個數字N,讓你把它拆成n(n<=50)個迴文數字的和,並輸出這些迴文數字(N<=10^1000)
2.分析:
(1)對於一個數字,我們先找儘可能接近他的會迴文數字,然後減去。但是這個迴文數字太難找了,怎麼辦?我們可以把當前數字前半部分對稱到後面去,比如123 其對應的會迴文數字為121。但是這裡就面臨一個問題:120對應的121比120大,所以我們這裡可以把12減1再對稱為111就可以了
(2)為了防止冗雜的判斷,我們為了保證迴文 + 小於原數字,直接取前一半減1在對稱。如10000->取前一半100->減99->對稱9999 不斷取剩餘數字的迴文,知道原數字減為0即可。
(3)特判:13取前一半減1對稱後變成了00,也就是如果減1後變為了0,這樣的只有1,所以保持1不動即可。還有10這個數字,保持不動對稱為11,減1為00,都不符合,所以特判為 9 + 1;
3.程式碼:
#include <iostream> #include<bits/stdc++.h> using namespace std; const int maxn = 1000 + 7; char num[maxn],num2[maxn],another[maxn],sub[maxn]; char ans[51][maxn]; char one[2] = "1"; bool judge(char *s){//判斷當前數字是否為迴文數字 int lens = strlen(s); for(int i = 0;i<lens/2;i++){ if(s[i]!=s[lens - i - 1]){ return false; } } return true; } void Decrease(char *s1,char *s2){//大數減法,s1 - s2並把結果賦值給s1去掉前導0 int len1 = strlen(s1); int len2 = strlen(s2); int i = len1-1; int j = len2-1; int flag = 0; while(i>=0&&j>=0){ if(s1[i] - '0'>=flag){ s1[i] = s1[i] - flag; flag = 0; } else{ s1[i] = s1[i] + 10 - flag; flag = 1; } if(s1[i]>=s2[j]){s1[i] = s1[i] -s2[j] + '0';} else{ s1[i] = s1[i] + 10 - s2[j] + '0'; flag = 1; } i--; j--; } while(flag&&i>=0){ if(s1[i] - '0'>=flag){ s1[i] = s1[i] - flag; flag = 0; } else{ s1[i] = s1[i] + 10 - flag; flag = 1; } i--; } //cout<<s1<<endl; int l = 0; bool flagd = false; memset(another,0,sizeof(another)); for(int k = 0;k<len1;k++){//去掉前導0 if(s1[k]=='0'&&!flagd)continue; else if(s1[k]!='0'&&!flagd){ flagd = true; another[l++] = s1[k]; } else if(flagd){ another[l++] = s1[k]; } } if(!l){another[l] = '0';l++;}//減法完為0 another[l] = '\0'; strcpy(s1,another);//複製 } void palindromic(char *s1,char *s2){//取s1的迴文串s2 int len1 = strlen(s1); if(len1==2&&s1[0]=='1'&&s1[1]=='0'){//特判 s2[0] = '9'; s2[1] = '\0'; return; } int len2 = (len1&1)?len1/2 + 1:len1/2; for(int i = 0;i<len2;i++){//取前一半 s2[i] = s1[i]; } s2[len2] = '\0'; Decrease(s2,one);//減1 if(s2[0]=='0'){//判斷1 s2[0] = '1'; } for(int i = len1-1,j = 0;j<i;i--,j++){ s2[i] = s2[j];//對稱 } s2[len1] = '\0'; } int main() { int T; scanf("%d",&T); int t = 0; while(T--){ scanf("%s",num); t++; int le = 0; while(num[0]!='0'&&le<=50){ le++; //cout<<"num:"<<num<<endl; if(judge(num)){//當前為迴文,直接結束 strcpy(ans[le++],num); break; } memset(sub,0,sizeof(sub)); palindromic(num,sub);//取回文數字sub //cout<<"sub:"<<sub<<endl; strcpy(ans[le++],sub);//儲存結果sub Decrease(num,sub);//num - sub } printf("Case #%d:\n%d\n",t,le); for(int i = 0;i<le;i++){ printf("%s\n",ans[i]); } } return 0; }