《算法竞赛入门经典(第二版)》第五章
思考题
无
示例程序
待补充
例题
例题5-7 丑数 (Ugly Numbers, UVa 136)
丑数是指不能被2,3,5以外的其他素数整除的数。把丑数从小到大排列起来,结果如下:
1,2,3,4,5,6,8,9,10,12,15,…
求第1500个丑数
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long int LL;
const int coeff[3]={2,3,5};
int main(){
priority_queue< LL,vector<LL>,greater<LL> > pq;
set<LL> s;
pq.push(1);
s.insert(1);
for(int i=1;;i++){
LL x=pq.top();
pq.pop();
if(i==1500){
cout<<"The 1500'th ugly number is "<<x<<"."<<endl;
break;
}
for(int j=0;j<3;j++){
LL x2=x*coeff[j];
if(!s.count(x2)){//检查是否将入队重复元素
pq.push(x2);
s.insert(x2);
}
}
}
return 0;
}
应用
大整数类 BigInteger
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
struct BigInteger{
static const int BASE=100000000;
static const int WIDTH=8;
vector<int> s;
BigInteger(long long num=0){
*this=num;
}
BigInteger operator=(long long num){
s.clear();
do{
s.push_back(num%BASE);
num/=BASE;
}while(num>0);
return *this;
}
BigInteger operator=(const string& str){
s.clear();
int x,len=(str.length()-1)/WIDTH+1;
for(int i=0;i<len;i++){
int end=str.length()-i*WIDTH;
int start=max(0,end-WIDTH);
sscanf(str.substr(start,end-start).c_str(),"%d",&x);
s.push_back(x);
}
return *this;
}
friend ostream& operator<<(ostream &out,const BigInteger& x);
friend istream& operator>>(istream &in,BigInteger& x);
BigInteger operator+(const BigInteger& b)const{
BigInteger c;
c.s.clear();
for(int i=0,g=0;;i++){//g为进位保留器
if(g==0&&i>=s.size()&&i>=b.s.size())//无进位且加数加完
break;
int x=g;//x为各段和
if(i<s.size())
x+=s[i];
if(i<b.s.size())
x+=b.s[i];
c.s.push_back(x%BASE);
g=x/BASE;
}
return c;
}
BigInteger operator+=(const BigInteger& b){
*this=*this+b;
return *this;
}
bool operator<(const BigInteger& b)const{
if(s.size()!=b.s.size())//先比段数
return s.size()<b.s.size();
for(int i=s.size()-1;i>=0;i--)
if(s[i]!=b.s[i])//再比各段大小
return s[i]<b.s[i];
return false;
}
bool operator>(const BigInteger& b){
return b<*this;
}
bool operator<=(const BigInteger& b){
return !(b<*this);
}
bool operator>=(const BigInteger& b){
return !(*this<b);
}
bool operator!=(const BigInteger& b){
return *this<b||b<*this;
}
bool operator==(const BigInteger& b){
return !(*this<b||b<*this);//可德摩根为!(*this<b)&&!(b<*this)
}
};
ostream& operator<<(ostream &out,const BigInteger& x){
out<<x.s.back();
for(int i=x.s.size()-2;i>=0;i--){
char buf[20];
sprintf(buf,"%08d",x.s[i]);
for(int j=0;j<strlen(buf);j++)
out<<buf[j];
}
return out;
}
istream& operator>>(istream &in,BigInteger& x){
string s;
if(!(in>>s))
return in;
x=s;
return in;
}
int main(){
BigInteger bi;
cin>>bi;
cout<<bi;
//bi=123456789;
return 0;
}
这里比较牛的一个操作是 ⌈ l e n g t h W I D T H ⌉ = ⌊ l e n g t h − 1 W I D T H ⌋ + 1 \lceil \ \frac{length}{WIDTH}\rceil=\lfloor \ \frac{length-1}{WIDTH}\rfloor+1 ⌈ WIDTHlength⌉=⌊ WIDTHlength−1⌋+1
习题
待补充
总结
- 关闭与stdio的同步可加快流的速度,常用的加速操作为
其中ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin.tie(0)
与cout.tie(0)
用于解除cin与cout的绑定,进一步加快执行效率; - 当题目有多种操作时,提取出指令之间的共同点,编写函数以减少重复代码,即“找动词”;
priority_quene< int,vector<int>,greater<int> > pq
中最后两个’>'尽量不要写在一起,可能会被编译器误认为是">>"运算符;- 获得[0,n]间随机数的方法:
rand()%n
Round(double(rand())/RAND_MAX*n)
- 把vector作为参数或返回值时,应尽量改成引用方式传递参数,以避免不必要的值被复制,数组同理。