《算法竞赛入门经典》Chap5

思考题

示例程序

待补充

例题

例题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= WIDTHlength1+1

习题

待补充

总结

  1. 关闭与stdio的同步可加快流的速度,常用的加速操作为
    ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    
    其中cin.tie(0)cout.tie(0)用于解除cin与cout的绑定,进一步加快执行效率;
  2. 当题目有多种操作时,提取出指令之间的共同点,编写函数以减少重复代码,即“找动词”;
  3. priority_quene< int,vector<int>,greater<int> > pq中最后两个’>'尽量不要写在一起,可能会被编译器误认为是">>"运算符;
  4. 获得[0,n]间随机数的方法:
    1. rand()%n
    2. Round(double(rand())/RAND_MAX*n)
  5. 把vector作为参数或返回值时,应尽量改成引用方式传递参数,以避免不必要的值被复制,数组同理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值