4 回文數
對於一個自然數n,若將n的各位數字反向排列所得的數n1與n相等,則稱n為回文數,例如2332。
若給定一個N( 2<=N<=16)進制數M(M的長度在一百位以內),如果M不是回文數,可以對其進行N進制加法,最終得到回文數。
例如對於十進制數79 STEP1 : 79 + 97 = 176 STEP2 : 176 + 671 = 847 STEP3 : 847 + 748 = 1595 STEP4 : 1595 +5951 = 7546 STEP5 : 7546 + 6457 = 14003 STEP6 : 14003 + 30041 = 44044
那么對於給定的N進制數M,請判斷其能否在30步以內(包括30步)得到回文數。
輸入格式
第一行包括一個正整數 N(2<=N<=16)。
第二行包括一個正整數M(一百位以內)。
輸出格式
如果可以在n步內得到回文數,輸出“STEP=n”,否則輸出“NO”。
輸入樣例1
10
79
輸出樣例1
STEP=6
輸入樣例2
8
665556
輸出樣例2
NO
Accepted
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
using namespace std;
void rever(string a){ //可用 reverse(a.begin(), a.end());代替
int i,j;
char temp;
int len=(int)a.size()-1;
if(len%2){
for(i=0,j=len-1;i!=j;i++,j--){
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
if(len%2==0){
for(i=0,j=len-1;i!=j-1;i++,j--){
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
string sum_str(string m,int n){
int temp = 0,i;
int flag=0;
string a;
int j=(int)m.size()-1;
for(i=0;i<m.size()&&j>=0;i++,j--){
temp=0;
if(m[i]>='0'&&m[i]<='9') temp+=(m[i]-'0');
if(m[j]>='0'&&m[j]<='9') temp+=(m[j]-'0');
if(m[i]>='A'&&m[i]<='Z')temp+=(m[i]-'A')+10;
if(m[j]>='A'&&m[j]<='Z')temp+=(m[j]-'A')+10;
if(flag==1){//進位1
temp++;
flag=0;
}
if(temp>=n){//大於n要進位
flag=1;
temp-=n;}
if(temp<10) temp+='0';
else temp=temp-10+'A';
a+=temp;
}
if(flag==1){
a=a+"1";
}
rever(a);
return a;
}
int judge(string m){
int i,j;
for(i=0,j=(int)m.size()-1;i<m.size()&&j>=0;i++,j--){
if(m[i]!=m[j]) return 0;
}
return 1;
}
int main() {
int n;
int step=0;
string m;
cin >> n;
cin >> m;
if(judge(m)) cout << "STEP=" <<step << endl;
else{
while(step<=30){
m=sum_str(m,n);
step++;
if(judge(m)){
cout << "STEP=" <<step << endl;
break;
}
}
}
if(step>30) {cout << "NO" << endl; }
return 0;
}
高精度計算加減乘除
5 數樓梯
樓梯有N階,上樓可以一步上一階,也可以一步上兩階。那么走到第N階樓梯共有多少種不同的走法呢?
輸入格式
一個正整數 N(1<=N<=5000),表示樓梯階數。
輸出格式
輸出一個數,表示走到第N階樓梯有多少種走法。
注意,數據范圍很大,即使是64位也可能不夠存。
輸入樣例1
4
輸出樣例1
5
輸入樣例2
400
輸出樣例2
28481229810848961175798893768146099561538008878230489098647719564596927140403
Accepted
(來源:洛谷)
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
using namespace std;
int len=1,fl[5005][5005]={0};//fl[k][i]--第k階台階所對應的走法數
void floor(int k){
int i;
for(i=1;i<=len;i++)
fl[k][i]=fl[k-1][i]+fl[k-2][i];
for(i=1;i<=len;i++){
if(fl[k][i]>=10){
fl[k][i+1]+=fl[k][i]/10;
fl[k][i]=fl[k][i]%10;
if(fl[k][len+1]) len++;
}
}
}
int main() {
int n;
cin >> n;
fl[1][1]=1;
fl[2][1]=2;
for(int i=3;i<=n;i++){
floor(i);
}
for(int i=len;i>=1;i--){
printf("%d",fl[n][i]);
}
return 0;
}
這道題我們可以論述一下遞推與遞歸的方法與區別
遞推一般用循環來解決,從已知條件到未知逐漸接近結果:
(1)將復雜運算分解為若干重復的簡單運算
(2)后一步驟建立在前一步驟之上
(3)計算每一步驟的方法相同
(4)從開始向后計算出結果
(5)使用循環結構,通過多次循環逐漸逼近結果
遞歸一般自己調用自己,從未知到已知,把規模大的、較難解決的問題變成規模較小的、易解決的同一問題。規模較小的問題又變成規模更小的問題,並且小到一定程度可以直接得出它的解,從而得到原來問題的解。
(1)每一次遞歸都縮小問題規模,直到問題足夠小
(2)使用選擇分支語句
(3)從后往開始逐步逼近
(4)達到最開始,再把初始值帶入往后逐一求解
6 A-B
已知兩個數A和B,求A-B的運算結果。
輸入格式
輸入包括兩個正整數A和B 。(0<A,B≤1e10086)
輸出格式
輸出A-B的運算結果。
輸入樣例1
3
2
輸出樣例1
在這里給出相應的輸出。例如:
1
輸入樣例2
11102356985410
2356985410235698
輸出樣例2
在這里給出相應的輸出。例如:
-2345883053250288
Wrong Answer
給出我的比較麻煩的代碼(只有90分,待修改)
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
using namespace std;
int sign=0;
string sub(string a,string b){
string ans;
int temp;
long long lena=(int)a.size();
long long lenb=(int)b.size();
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
long long i;
int flag=0;
if(lena<lenb){
sign=1;
for(i=0;i<lenb;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
temp=bt-at;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
// if(temp<0) sign=1;
}
if(lena==lenb){
if(a<b) sign=1;
if(sign){
for(i=0;i<lenb;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
temp=bt-at;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
// if(temp<0) sign=1;
}
else{
for(i=0;i<lena;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
temp=at-bt;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
//if(temp<0) sign=1;
}
}
if(lena>lenb){
for(i=0;i<lena;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
temp=at-bt;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
// if(temp<0) sign=1;
}
reverse(ans.begin(), ans.end());
return ans;
}
int main() {
string a,b;
string ans;
int flag=0;
cin >> a;
getchar();
cin >> b;
getchar();
if(a==b) {
cout << "0" << endl;
return 0;
}
ans=sub(a,b);
if(sign) cout <<"-";
for(long long i=0;i<ans.size();i++){
if(flag==0&&ans[i]!='0'){
cout << ans[i];
flag=1;
}
else if(flag==1){
cout << ans[i];
}
}
return 0;
}
后來詢問發現,第一版錯的原因在於當兩個數長度不相等時,未對數字進行相應的初始化。
更改后終於AC:
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
using namespace std;
int sign=0;
string sub(string a,string b){
string ans;
int lena=(int)a.size();
int lenb=(int)b.size();
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int i;
int flag=0;
if(lena<lenb){
sign=1;
for(i=lena;i<lenb;i++){
a+='\0';
}
for(i=0;i<lenb;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
int temp=bt-at;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
}
if(lena==lenb){
if(a<b) sign=1;
if(sign){
for(i=0;i<lenb;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
int temp=bt-at;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}}
else{
for(i=0;i<lena;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
int temp=at-bt;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
}
}
if(lena>lenb){
for(i=lenb;i<lena;i++){
b+=' ';
}
for(i=0;i<lena;i++){
int at=0,bt=0;
if(a[i]>='0'&&a[i]<='9') at=a[i]-'0';
if(b[i]>='0'&&b[i]<='9') bt=b[i]-'0';
int temp=at-bt;
if(flag==1) {
temp--;
flag=0;
}
if(temp<0){
temp+=10;
flag=1;
}
ans+=temp+'0';
}
}
reverse(ans.begin(), ans.end());
return ans;
}
int main() {
string a={0},b={0};
string ans;
int flag=0;
cin >> a;
getchar();
cin >> b;
// getchar();
if(a==b) {
cout << "0" << endl;
return 0;
}
ans=sub(a,b);
if(sign) cout <<"-";
for(int i=0;i<ans.size();i++){
if(flag==0&&ans[i]!='0'){
cout << ans[i];
flag=1;
}
else if(flag==1){
cout << ans[i];
}
}
return 0;
}
Accepted
(來源:大數減法)
第二版更加簡練,把判斷的部分放在main函數中,且AC了
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
using namespace std;
string sub(string a,string b,int len){
int i;
string ans;
int lenb=(int)b.size();
for(i=0;i<lenb;i++){
if(a[i]>=b[i]){ //不需要向前借1
ans+=a[i]-b[i]+'0';
}
else{//需要向前借1
ans+=a[i]+10-b[i]+'0';
a[i+1]--;
}
}
for(;i<len;i++){
ans+=a[i];
}
reverse(ans.begin(), ans.end());
return ans;
}
int main() {
string a,b;
string ans;
int i;
int flag=0;
cin >> a >> b;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int lena=(int)a.size();
int lenb=(int)b.size();
if(lena>lenb){ ////若減數長度 > 被減數長度,正常減
ans=sub(a,b,lena);
for(i=0;i<ans.size();i++){
if(flag==0&&ans[i]>'0'&&ans[i]<='9') {
cout << ans[i];
flag=1;
}
else if(flag==1) cout << ans[i];
}
return 0;
}
else if(lena<lenb){//若減數長度 < 被減數長度,被減數-減數
cout <<"-";
ans=sub(b,a,lenb);
for(i=0;i<ans.size();i++){
if(flag==0&&ans[i]>'0'&&ans[i]<='9') {
cout << ans[i];
flag=1;
}
else if(flag==1) cout << ans[i];
}
return 0;
}
else{//若減數長度 == 被減數,判斷兩個數的大小
if(a>b){
ans=sub(a,b,lena);
for(i=0;i<ans.size();i++){
if(flag==0&&ans[i]>'0'&&ans[i]<='9') {
cout << ans[i];
flag=1;
}
else if(flag==1) cout << ans[i];
}
}
else if(a<b){
cout <<"-";
ans=sub(b,a,lenb);
for(i=0;i<ans.size();i++){
if(flag==0&&ans[i]>'0'&&ans[i]<='9') {
cout << ans[i];
flag=1;
}
else if(flag==1) cout << ans[i];
}
}
else{
cout << "0" << endl;
}
}
return 0;
}
7 高精度除法
給兩個正整數 a,b,求 a/b的整數部分。
輸入格式
輸入共兩行,每行一個正整數,分別表示 a和b。 50%數據,a,b均小於1e18, 50%數據,a,b均小於1e500。
輸出格式
輸出一個整數,表示a/b的整數部分。
輸入樣例1
3
2
輸出樣例1
1
輸入樣例
24781236498237462378425347823652387423654238752372365327862
8934457724628746
輸出樣例2
2773669903874014740488146558678531750078864
Accepted
(來源:大數除法)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=11000;
int sub(int *a,int *b,int lena,int lenb)
{
if(lena<lenb) return -1;//如果a小於b,則返回-1
if(lena==lenb)
{
for(int i=lena-1;i>=0;i--)
if(a[i]>b[i]) break;
else if(a[i]<b[i]) return -1;//如果a小於b,則返回-1
}
for(int i=0;i<lena;i++)//高精度減法
{
a[i]-=b[i];
if(a[i]<0) {a[i]+=10;a[i+1]--;}
}
for(int i=lena-1;i>=0;i--)
if(a[i]) return i+1;//返回差的位數
return 0;//返回差的位數
}
string div(string n1,string n2)//n1,n2是字符串表示的被除數
{
string s,v;//s存商,v存余數
int a[L]={0},b[L]={0},r[L]={0},lena=n1.size(),lenb=n2.size(),i;//a,b是整形數組表示被除數,除數
for(i=lena-1;i>=0;i--) a[lena-1-i]=n1[i]-'0';
for(i=lenb-1;i>=0;i--) b[lenb-1-i]=n2[i]-'0';
if(lena<lenb || (lena==lenb && n1<n2)) {
return "0";
}//如果a<b,則商為0
int t=lena-lenb;//除被數和除數的位數之差
for(int i=lena-1;i>=0;i--)//將除數擴大10^t倍
if(i>=t) b[i]=b[i-t];
else b[i]=0;
lenb=lena;
for(int j=0;j<=t;j++)
{
int temp;
while((temp=sub(a,b+j,lena,lenb-j))>=0)//如果被除數比除數大繼續減
{
lena=temp;
r[t-j]++;
}
}
for(i=0;i<L-10;i++) {r[i+1]+=r[i]/10;r[i]%=10;}//統一處理進位 ??
while(!r[i]) i--;//將整形數組表示的商轉化成字符串表示的
while(i>=0) s+=r[i--]+'0';
return s;
}
int main()
{
string a,b;
cin>>a>>b;
cout<<div(a,b)<<endl;
return 0;
}
