ACM必做50题的解题高精度.docx
《ACM必做50题的解题高精度.docx》由会员分享,可在线阅读,更多相关《ACM必做50题的解题高精度.docx(16页珍藏版)》请在冰豆网上搜索。
ACM必做50题的解题高精度
POJ1001Exponentiation
高精度数的计算,以前在网上看到过一个计算大数阶乘比如10000000!
的算法,总体思想就是将结果用数组保存起来,然后将结果的每一位与乘数相乘,当然还有进位...
有了这个算法的思想,这个题思路就可以是:
先将输入的小数转换成一个整数,当然这个整数肯定能够用int类型的变量保存,比如1.2345,通过函数removeDot()将它转化成12345,然后利用大数阶乘的思想计算12345*12345.....*12345,最后的就是输出了,这个要考虑的情况比较多,因为这个也WA了5次才AC(笨的要死),情况虽多,但不难.
这道题是高精度计算的,不算很难,但是很繁琐,尤其是对输入输出的要求。
被这道题搞了好久,耐心来,一点一点调试,总会成功的。
#include
#include
#include
usingnamespacestd;
charans[10];
charres[2][205];
__int64ps;//有几位小数点
intlen;//长度,R的有效长度
//计算c=b*a
voidMultiply(char*b,intbt,char*a,intat,char*c)
{
inti,j;
intup=0;
for(i=0;i{
up=0;
for(j=0;j{
intt;
if(c[i+j]==0)
c[i+j]='0';
t=(a[i]-48)*(b[j]-48)+c[i+j]-48+up;
if(t>=10)
{
up=t/10;
t=t%10;
c[i+j]=t+48;
if(j==(bt-1))
c[i+j+1]=(up+48);
}
else
{
c[i+j]=t+48;
up=0;
}
}
}
}
intmain()
{
stringstr;
intn;
inti,j;
ints,t;
intpos;
while(cin>>str>>n)
{
i=5;
pos=str.find('.',0);
if(pos<0)//没有小数点
{
ps=0;
//zs=zs*n;//后面为0的总数
}
else//有小数点
{
ps=(5-pos);
ps=ps*n;//小数位总数
}
memset(ans,0,sizeof(ans));
memset(res[0],0,sizeof(res[0]));
memset(res[1],0,sizeof(res[1]));
t=5;
s=0;
while(str[s]=='0'||str[s]=='.')
s++;
j=0;
for(i=t;i>=s;--i)
{
if(str[i]=='.')
continue;
ans[j]=str[i];
j++;
}
len=j;
strcpy(res[0],ans);
strcpy(res[1],ans);
for(i=2;i<=n;++i)
{
memset(res[(i+1)%2],0,sizeof(res[0]));
Multiply(res[i%2],strlen(res[i%2]),ans,len,res[(i+1)%2]);
}
intL=strlen(res[(n+1)%2]);
intd=(n+1)%2;
if(ps>0)
{
j=0;
while(res[d][j]=='0')
j++;
if(ps>=L)
{
printf(".");
for(i=ps-1;i>=j;--i)
{
if(i>=L)
printf("0");
else
printf("%c",res[(n+1)%2][i]);
}
}
else
{
if(j>=ps)
{
for(i=L-1;i>=ps;--i)
printf("%c",res[(n+1)%2][i]);
}
else
{
for(i=L-1;i>=j;--i)
{
if(i==ps)
{
printf("%c.",res[(n+1)%2][i]);
}
else
printf("%c",res[(n+1)%2][i]);
}
}
}
}
else
{
for(i=L-1;i>=0;--i)
printf("%c",res[(n+1)%2][i]);
}
printf("\n");
}
return0;
}
POJ1047RoundandRoundWeGo
题意:
输入一个数,要求判该数是否为循环数.
依次将该数分别于2到len(输入的数的位数)相乘,在乘的过程中,判断数发生了变化没有,如果发生了变化,则直接输出该数不是循环数,没有必要再继续乘下去,而如果是循环数,则一直需要乘下去.
#include
#include
#include
#include
usingnamespacestd;
intnum[70];
intans[70];
charss[70];
boolmatch[70];
intmain()
{
inti,j,k,len;
boolflag;
while(scanf("%s",ss)!
=EOF)
{
len=strlen(ss);
for(i=len-1,j=0;i>=0;i--,j++)
num[j]=ss[i]-'0';
for(i=2;i<=len;i++)
{
memset(ans,0,sizeof(ans));
for(j=0;jans[j]=num[j]*i;
for(j=0;jif(ans[j]>=10)
{
ans[j+1]+=ans[j]/10;
ans[j]%=10;
}
memset(match,0,sizeof(match));//match数组用来标记数的匹配情况
flag=true;
for(j=0;j{
k=0;
while(k{
if(ans[k]==num[j]&&!
match[k])//两数字相等且没有进行标记
{
match[k]=true;
break;
}
k++;
}
if(k==len)//此时说明相乘后的结果发生了改变
{
flag=false;
break;
}
}
if(!
flag)
{
printf("%sisnotcyclic\n",ss);
break;
}
}
if(flag)
printf("%siscyclic\n",ss);
}
system("pause");
return0;
}
POJ1131OctalFractions
给定一个八进制的小数题目要求你把它转换为十进制小数,转换后小数的位数是转换前八进制小数位数的3倍且不输出末尾无意义的零(即后置零).我采用的方法是乘10然后对8取整(现在假设将p进制的小数转换为n进制,同样采用乘n取整:
),每转换一位,都必须从最低位s[len-1]开始至小数的最高位(即小数点后的一位),每次计算积g=a[j]*n+k(其中k为下一位积的进位),本位进位数k=g/p,积在本位存入s[j]=g%p;最后的整数k作为转换的一位存放于转换结果字符串中。
#include
#include
#include
#include
usingnamespacestd;
chars1[20],s2[50],s3[20];
intmain()
{
inti,t,j,k,g,l,len;;
while(scanf("%s",s1)!
=EOF)
{
l=strlen(s1);
strcpy(s3,s1);
len=3*(l-2);
t=0;
s2[0]='0';
s2[1]='.';
j=2;
while(t{
k=0;
t++;
for(i=l-1;i>1;i--)//从最低位开始采用乘10对8取整
{
g=(s1[i]-'0')*10+k;
k=g/8;
s1[i]=g%8+'0';
}
s2[j]=k+'0';
j++;
}
s2[j]='\0';
printf("%s[8]=",s3);
j--;
while(s2[j]=='0')//找出最后一个不为0的数的位置
j--;
for(i=0;i<=j;i++)//去掉后置0进行的输出
printf("%c",s2[i]);
printf("[10]\n");
}
system("pause");
return0;
}
ACM——POJ1503(IntegerInquiry)
题目解析:
水题一道。
就是大数加法,循环移位。
注意输入数据有以0开头的整数,所以要用strcmp判断而不是直接判断[0]位是否为0。
#include
#include
usingnamespacestd;
intmain()
{
//输出字符串至多为100个100位数的和,给102位,因为我不需要最后一位\0作定位符
charm_Sum[102];
//初始化这102位为'0'
memset(m_Sum,48,102);
//定位输出字符串的位置,用于加法。
定位输出字符串的位置,用于进位
intm_Pos_Sum,m_Pos_Sum_Temp;
//输入字符串长度至多为100,给101位,因为我需要\0位控制结束
charm_Input[101];
//输入字符串的长度
intm_Length_Input;
while
(1)
{
//初始化为\0
memset(m_Input,0,101);
//输入数据
scanf("%s",m_Input);
//输入的数据有可能是以0开头的,不能直接判断[0]是否为0,得用strcmp
if(strcmp(m_Input,"0")==0)
break;
else
{
//计算输入字符串的长度
m_Length_Input=strlen(m_Input);
//定位输出字符串的位置至最后一位,即101
m_Pos_Sum=101;
//从这个字符串的最低位开始加,[m_Length_Input-1]永远表示需要加的那一位
while(m_Length_Input>0)
{
//做单个位置的加法,注意需减48
m_Sum[m_Pos_Sum]+=(m_Input[m_Length_Input-1]-48);
//定位进位位置
m_Pos_Sum_Temp=m_Pos_Sum;
//如果大于9,需要进位,且是循环进位
while(m_Sum[m_Pos_Sum_Temp]>'9')
{
//这一位减10,前一位加1
m_Sum[m_Pos_Sum_Temp]-=10;
m_Sum[--m_Pos_Sum_Temp]+=1;
}
//输入字符串与输出字符串均往前移1位
--m_Length_Input;
--m_Pos_Sum;
}
}
}
//输出结果,先找到第一个不为0的位置
intm_Cycle;
for(m_Cycle=0;m_Cycle<102;++m_Cycle)
{
if(m_Sum[m_Cycle]!
='0')
break;
}
//从该位置起,输出后面所有
for(;m_Cycle<102;++m_Cycle)
printf("%c",m_Sum[m_Cycle]);
printf("\n");
system("pause");
return0;
}
POJ1504AddingReversedNumbers水题
此题主要就是数字的前后倒置,这是解决问题的关键,当然可以用字符串进行计算,但是这样我认为会比较复杂(没有测试),所以我采取了另一种方法,具体见reverse函数!
#include
intmain()
{
intreverse(intx);
intcases,x1,x2,sum;
scanf("%d",&cases);
while(cases--)
{
scanf("%d%d",&x1,&x2);
sum=reverse(x1)+reverse(x2);
printf("%d\n",reverse(sum));
}
return0;
}
intreverse(intx)
{
intb,sum=0;
while(x!
=0)
{
b=x%10;
x=x/10;
sum=sum*10+b;
}
returnsum;
}
poj1060(SortingItAllOut)
拓扑排序问题。
也可以用传递闭包做,但是还没有看,不会.
最主要的是要理解好题意:
wherexxxisthenumberofrelationsprocessedatthetimeeitherasortedsequenceisdeterminedoraninconsistencyisfound,whichevercomesfirst,。
意思就是依次输入各个relation,一旦发现可以确定拓扑序列则输出序列,后面的relations忽略(即使发现有矛盾);一旦发现有矛盾(即环),则输出,后面relations也忽略。
这个题意我倒是一开始就理解了,但是有个简单的问题我没有想到,应该先判断是否有矛盾(环),等输完最后一个relations后再判断是否有多个拓扑序列。
如果没有考虑到这一点对于一些样例输入是可以正确输出的,但是对于如下的样例输入则会输出Sortedsequencecannotbedetermined.(实际上应该输出Inconsistencyfoundafter12relations.):
1112
KBEDGH
GIJAFC
再注意到这一点就可以避免错误了,应该就差不多能过了。
#include
usingnamespacestd;
classpoly{
public:
poly(intN=0){
n=N;
p=newint[n*sizeof(int)];
for(inti=0;i}
poly&operator=(constpoly&s){
n=s.n;
for(inti=n-1;i>=0;i--)
p[i]=s.p[i];
while(!
s.p[n-1])n--;
return*this;
}
~poly(){if(p)delete[]p;}
voidset(constpoly&a,constpoly&b){
n=abs(a.n-b.n)+1;
for(inti=0;ip[n-1]=1;
}
friendpolyoperator*(constpoly&a,constpoly&b){
polyd(a.n+b.n+1);
d.n=1;
inti,j;
for(i=0;iif(a.p[i])
for(j=0;jif(b.p[j]){
d.p[i+j]=(d.p[i+j]+1)%2;
if(i+j>d.n-1)d.n=i+j+1;
}
returnd;
}
friendpolyoperator-(constpoly&a,constpoly&b){
polyd(max(a.n,b.n));
for(inti=0;id.p[i]=(a.p[i]-b.p[i])%2;
if(d.p[i]<0)d.p[i]+=2;
}
returnd;
}
friendbooloperator>(constpoly&a,constpoly&b){
if(a.n>b.n)return1;
if(a.n==b.n)
for(inti=a.n-1;i>=0;i--)
if(a.p[i]>b.p[i])return1;
return0;
}
friendostream&operator<<(ostream&out,constpoly&s){
cout<for(inti=s.n-1;i>=0;i--)
cout<<''<returnout;
}
friendistream&operator>>(istream&in,poly&s){
cin>>s.n;
for(inti=s.n-1;i>=0;i--)
cin>>s.p[i];
returnin;
}
private:
intn,*p;
}a(1001),b(1001),c(1001),d(2002),e(1001);
intmain()
{
intt;
cin>>t;
while(t--){
cin>>a>>b>>c;
d=a*b;
while(d>c){
e.set(d,c);
d=d-c*e;
}
cout<}
}