进制转换
不用字符串模拟的情况
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int main(){
unsigned int n;
while (cin>>n) {
vector<int> arr;
while(n){
arr.push_back(n%2);
n/=2;
}
for(int i=arr.size()-1;i>=0;i--){
cout<<arr[i];
}
cout<<endl;
}
return 0;
} 核心:
- 首先取余数,然后整除2
- vector存储,之后逆序输出,但是如果用栈不用了
下面是用栈解决的情况:
#include <iostream>
#include<stack>
using namespace std;
int main(){
unsigned int num;
stack<int> s;
while(cin>>num){
while(num){
s.push(num%2);
num/=2;
}
while(!s.empty()){
cout<<s.top();
s.pop();
//因为这里有pop,所以可以将stack在循环外定义,不用针对每个二进制数建立一个stack
}
cout<<endl;
}
} 需要用字符串模拟的情况
在很多时候题目暗示了数字会很大(30位),在这种情况下用整型就无法表示了。一些基本数据类型的范围如下:
例题
进制转换
来源:牛客网
将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。
输入描述:
多组数据,每行为一个长度不超过30位的十进制非负整数。
(注意是10进制数字的个数可能有30个,而非30bits的整数)
输出描述:
每行输出对应的二进制数。
//这个数据会太长,所以需要用字符串模拟
#include <iostream>
#include<string>
#include<vector>
using namespace std;
//需要重写除法
string Div(string a ,int x){
int remain=0;
for(int i=0;i<a.size();i++){
int current=remain*10+a[i]-'0';//余数*10+后一位除以x即可
a[i]=current/x+'0';//保存形式是字符,所以应该加‘0’
remain=current%x;
}
int pos=0;
while(a[pos]=='0')
pos++;
return a.substr(pos);//去除前置多余的0
}
int main(){
string str;
while(cin>>str){
vector<int> ve;
while(str.size()!=0){
ve.push_back((*(str.end()-1)-'0')%2);
//ve.push_back(str[str.size()-1]-'0')%2);
str=Div(str, 2);
}
for(int i=ve.size()-1;i>=0;i--)
cout<<ve[i];
cout<<endl;
}
return 0;
} 字符串除法模版
string Div(string a ,int x){
int remain=0;
for(int i=0;i<a.size();i++){
int current=remain*10+a[i]-'0';//余数*10+后一位除以x即可
a[i]=current/x+'0';//保存形式是字符,所以应该加‘0’
remain=current%x;
}
int pos=0;
while(a[pos]=='0')
pos++;
return a.substr(pos);//去除前置多余的0
} 记忆点⚠️:
- 需要一个余数变量remain和一个当前的被除数变量current
- 遍历字符串
- cur=re*10+a[i]-'0';a[i]=cur/x+'0';remain=current%x;
- 使用一个数组就行了,不必开辟新的数组
- 需要将前置的多余的0去掉(substr)
字符串乘法模版
string Multiple(string str,int x){
int carry=0;
for(int i=str.size()-1;i>-1;i--){
int cur=x*(str[i]-'0')+carry;
str[i]=cur%10+'0';
carry=cur/10;
}
if(carry)
str="1"+str;
return str;
} 字符串加法模版
string Add(string str,int x){
int carry=x;
for(int i=str.size()-1;i>-1;i--){
int cur=(str[i]-'0')+carry;
str[i]=cur%10+'0';
carry=cur/10;
}
if(carry)
str="1"+str;
return str;
} ⚠️记忆点:
- 进位carry和当前cur
- cur=x*(str[i]-'0')+carry.算str[i],算carry
- cur=str[i]-'0'+carry.算str[i],算carry
最大公因数/公倍数模版
//递归版
int GCD(int a,int b){
if(!b)
return a;
else
return GCD(b, a%b);
}
//非递归版
int gcd(int a,int b) {
if(!b)
return a;
int c;
while(b) {
c=b;
b=a%b;
a=c;
}
}
//lcm
int LCM(int a,int b){
return b/gcd(a,b)*a;
//先除后乘,以免a*b溢出
} 素数
素数的判断分为筛法和非筛法,其中筛法更加重要和常用。
非筛法
非筛法针对于判断某个数是否是素数,只需要在[2,bound]内判断是否可以整除就行,但是很明显sqrt()函数是一个计算起来比较困难的函数,不应该在for循环中使用这个函数,应该提前定义一个变量将其计算出来。
筛法
如果要判断某个范围内有多少素数,那么用暴力遍历的方法就不好了(时间复杂度太大),必须用筛法解决。
//素数筛法
#include <iostream>
#include <cstdio>
#include<vector>
using namespace std;
const int MAXN=10001;
vector<int> prime;
bool isPrime[MAXN];
void Initial(){
for(int i=0;i<MAXN;i++){
isPrime[i]=true;
}
//全部初始化为true,即首先默认全是素数
isPrime[0]=false;
isPrime[1]=false;
for(int i=2;i<MAXN;i++){
if(!isPrime[i])
continue;
//如果是素数,就推入向量
prime.push_back(i);
//从i^2开始之后i的倍数都是素数,i到i*i之间不必算(i*k(k<i))已经被k的倍数计算过了,可以理解成某种剪枝
for(int j=i*i;j<MAXN;j+=i)
isPrime[j]=false;
}
return;
} 注意点⚠️:
- prime向量存储素数;isPrime数组判断是不是素数
- 数组初始化全部是true,isPrime[0]=false; isPrime[1]=false;
- 从2到MAXN,如果isPrime为假就跳过;如果为真就将i放入向量中并从i*i开始的每个倍数都将isPrime设置为真
快速幂
LL qpow(LL a, LL b, LL MOD) {//a 的 n 次方(可取模)
LL ans = 1;
while (b) {
if (b & 1) {
//若当前位是1
ans *= a;
ans %= MOD;
}
b >>= 1;
//byouyiyiwei
a *= a;
a %= MOD;
}
return ans;
} 总体思想就是:每次都要将a平方,然后根据b当前位数上是否为1来决定需不需要在这个位置上累乘

京公网安备 11010502036488号