华师一附中OI组
标题:
P2005 A/B Problem II
[打印本页]
作者:
admin
时间:
2021-5-14 17:04
标题:
P2005 A/B Problem II
https://www.luogu.com.cn/problem/P2005
题目背景
为了让大家紧张的心情放松一下,这一题题是一道非常简单的题目。
题目描述
给出正整数N和M,请你计算N div M(N/M的下取整)。
输入格式
两行,两个正整数,N和M。
输出格式
一行,一个整数,表示N div M。
输入输出样例
输入 #1复制
1000
333
输出 #1复制
3
说明/提示
• 对于60%的数据:N,M ≤ 750!,答案≤ 7!。
• 对于100%的数据:N,M ≤ 6250!,答案≤ 13!。
请注意:上面的两句话并不是感叹句,而是陈述句。标点符号使用没有错误。
作者:
admin
时间:
2021-5-14 17:09
估计下N和M有多少位,敲了个高精度阶乘,算了半分钟,得出750!有21012位。这么大的数字,存起来还需要考虑数组的长度,假设22000位吧。
第一种方法,硬除。22000位的大数除普通longlong整数,也就只有22000次求商和取余,不会超时。
第二种方法,二分法。这个就比较新颖了,我们假设商的范围是L-R之间,去之间值M,和除数M做单精度乘法,得到乘积X,看看X和N的大小,
作者:
admin
时间:
2021-5-14 18:04
#include <bits/stdc++.h>
using namespace std;
string A,B,C; //A/B=C
string B09[10]; // 除数的0-9倍
bool isbig(string X,string Y) //字符串当数字比较大小
{
int lx=X.size(),ly=Y.size();
return (lx>ly)||(lx==ly && X>=Y);
}
string add(string A,string B) //基本高精加
{
string C="";
if (A.size()<B.size()) swap(A,B);
int la=A.size(),lb=B.size(),i;
for (i=lb+1; i<=la; i++) B="0"+B;
int j=0;
for (i=la-1; i>=0; i--)
{
int x=A[i]-'0'+B[i]-'0'+j;
j=x/10;
x=x%10;
C=char(x+'0')+C;
}
if (j) C="1"+C;
return C;
}
string sub(string A,string B) //基本高精减
{
string C="";
int la=A.size(),lb=B.size(),i,j=0,x;
for (i=lb+1; i<=la; i++) B="0"+B;
for (i=la-1; i>=0; i--)
{
x=A[i]-B[i]-j;
if (x<0)
{
j=1;
x+=10;
}
else j=0;
C=char(x+'0')+C;
}
int p=0;
while (C[p]=='0' && p<la-1) p++;
return C.substr(p);
}
void CB09(string B)
{
B09[0]="0",B09[1]=B;
for (int i=2; i<=9; i++)B09[i]=add(B09[i-1],B);
///for (int i=0; i<=9; i++) cout<<B09[i]<<endl;
}
int main()
{
cin>>A>>B;
CB09(B);
int la=A.size(),lb=B.size(),p;
string TA=A.substr(0,lb);
if (isbig(TA,B)) p=lb;
else
{
TA=TA+A[lb];
p=lb+1;
}
for(; p<=la; p++)
{
int k=9;
while (!isbig(TA,B09[k]))k--;
C=C+char(k+'0');
//cout<<TA<<' '<<C<<endl;
TA=sub(TA,B09[k]);
//cout<<TA<<endl;
TA=TA+A[p];
while (TA[0]=='0' && TA.size()>1) TA.erase(0,1);//去前面的0
}
cout<<C;
return 0;
}
复制代码
作者:
admin
时间:
2021-5-16 10:50
也可以用二分法来做这个题,显然,这个题满足二分法的条件,若X*B>A,则所有>=X的都不满足条件,若X*B<=A,则有可能在这个区间内找到答案。
先写一个不高精度的,典型的二分找下界。等下我们用点新玩意,高精度的运算符的重载。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL A,B,C,L,R,M,ANS;
int main()
{
cin>>A>>B;
L=0;
R=6227020800l;
while (L<=R)
{
M=(L+R)/2;
X=M*B;
if (X<=A)
{
ANS=M;
L=M+1;
}
else if (X>A) R=M-1;
}
cout<<ANS;
return 0;
}
复制代码
作者:
admin
时间:
2021-5-16 20:10
加入高精度过程,这里为了统一,我采用运算符重定义的做法,用结构题BigNum表示一个数,带两个变量,一个有效长度l和一个数组a。
重新定义了几个运算符:
1、<= 这个比较简单,短的比较小长的比较大,长度相等的话就从从第一个开始比较,不同的数字就比出来了结果。
2、* 大整数相乘 这个也很简单,标准的矩阵乘法,最后处理进位和长度,一般来说n位数*m位数得到n+m或者n+m-1位。(0没有考虑)
3、+ 分两个,大+小或者大+大。这都是以前的范例程序
4、- 这里只有一个M+1和M-1。但是也标准的写一个,注意%的使用,我这里比较巧妙。有可能减很大的数字,注意。
5、/ 大除小,基本的355/113的做法 但是多了一个去前面的0的过程,这里也可以类似上面的先比较再除,
我写了十几分钟,基本没有调试,一下就AC了,因为我这些基本功很到位的,你做了多少时间呢?
附·AC代码
#include <bits/stdc++.h>
using namespace std;
struct BigNum
{
int l;//位数
int a[22000];
BigNum()//初始化
{
memset(a,sizeof(a),0);
l=1;
}
void pp() //输出
{
for (int i=l-1; i>=0; i--) cout<<a[i];
cout<<' ';
}
} A,B,C,L,R,M,X,ANS;
bool operator <= (BigNum A,BigNum B)// 大的比大的
{
if(A.l>B.l) return 0;
if(A.l<B.l) return 1;
for (int i=A.l-1; i>=0; i--) // 这个比较精妙
if (A.a[i]<B.a[i]) return 1;
else if (A.a[i]>B.a[i]) return 0;
return 1;
}
BigNum operator * (BigNum A,BigNum B)// 大的乘大的
{
BigNum C;
int i,j,x;
C.l=A.l+B.l;
for (i=0; i<=C.l-1; i++) C.a[i]=0;
for (i=0; i<=A.l-1; i++)
for (j=0; j<=B.l-1; j++)
C.a[i+j]+=A.a[i]*B.a[j];
for (i=0; i<=C.l-1; i++)
{
x=C.a[i];
C.a[i]=x%10;
C.a[i+1]+=x/10;
}
while (C.a[C.l-1]==0 && C.l>1) C.l--;
return C;
}
BigNum operator + (BigNum A,BigNum B)// 大的加大的
{
if (A.l<B.l) swap(A,B);
int x,i;
for (i=0; i<=B.l-1; i++) A.a[i]+=B.a[i];
for (i=0; i<=A.l-1; i++)
{
x=A.a[i];
A.a[i]=x%10;
A.a[i+1]+=x/10;
}
if (A.a[A.l]>0)A.l++;
return A;
}
BigNum operator + (BigNum A,int b)
{
int x,i;
A.a[0]+=b;
for (i=0; i<=A.l-1; i++)
{
x=A.a[i];
A.a[i]=x%10;
A.a[i+1]+=x/10;
}
if (A.a[A.l]>0) A.l++;
return A;
}
BigNum operator - (BigNum A,int b)
{
int x,i;
A.a[0]-=b;
for (i=0; i<=A.l-1; i++)
{
x=A.a[i];
if (x<0) //这个我觉得写的很好
{
A.a[i]=x%10+10;
A.a[i+1]+=(x/10-1);
}
}
while (A.a[A.l-1]==0 && A.l>0) A.l--;
return A;
}
BigNum operator / (BigNum A,int b)
{
int i,x=0;
for (i=A.l-1; i>=0; i--)
{
x=10*x+A.a[i];
A.a[i]=x/b;
x=x%b;
}
while (A.a[A.l-1]==0 && A.l>0) A.l--;
return A;
}
BigNum Ch(string s)
{
int l=s.size();
BigNum A;
A.l=l;
for (int i=0; i<=l; i++) A.a[i]=s[l-1-i]-'0';
return A;
}
int main()
{
string sa,sb;
cin>>sa>>sb;
A=Ch(sa),B=Ch(sb);
L=Ch("0"),R=Ch("99999999999");
while (L<=R)
{
M=(R+L)/2;
X=M*B;
//L.pp(),R.pp(),M.pp(),X.pp();
//cout<<endl;
if (X<=A)
{
ANS=M;
L=M+1;
}
else R=M-1;
}
ANS.pp();
return 0;
}
复制代码
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2