做题小技巧(持续更新)
1.拆分数字x(可以很大噢)
int x,a[10005],c=0;//a[]数组存放拆分出来的每个数字,c用于标记数字在数组里存放的位置
scanf("%d",&x);
while(x){
a[c++]=x%10;
x/=10;
}
for(int i=c-1;i>=0;i--)//正序输出
printf("%d ",a[i]);
2.关于长度:
字符串数组长度:strlen()
整型数组长度:sizeof(arr)/sizeof( int )
注意:这里得到的是数组的总长度(即我们定义它的时候的大小),而不是数组中存放有意义的数据的个数
(实在不行就用定义一个量来追踪它就好啦)
3.查找一个数n的全部因子:(或者是因子的个数)
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
int a[10005];//装n的所有因子
int z=0;//辅助数组装因子的位置
scanf("%d",&n);
for(int i=1;i*i<=n;i++){
if(n%i==0){
a[z++]=i;
if(i!=(n/i)){//因为是在n/2前找所以可以用这个方法来查找n/2后的符合条件的数
a[z++]=n/i;
}
}
}
return 0;
}
4.找出一定范围x的素数
方法一:埃氏筛法
#include <bits/stdc++.h>
using namespace std;
int visit[100005]={0};//先假设全部都为素数
//0为素数 1为非素数
int main()
{
int x;
scanf("%d",&x);
for(int i=2;i<=x;i++){
if(!visit[i])
for(int j=i*i;j<=x;j+=i)
visit[j]=1;
}
for(int i=2;i<=x;i++)
if(!visit[i])
printf("%d ",i);
return 0;
}
这里的ii做了一个小优化,因为i(2 ~ i-1)在2~i-1时已经被筛去辽
但是,埃氏筛法有一个弊端,就是重复判断同一个数,重复筛去同一个数,这也会浪费时间,当数据很大时也可能会超时。
为了解决这个弊端,我们引进一种新的方法:欧拉筛法。
方法二:欧拉筛法
(它可以让每个合数只被它最小的质因子筛选一次!!!超厉害!!!他也太聪明了叭!!!!)
#include <bits/stdc++.h>
using namespace std;
//设0为素数 1为非素数
int visit[100005]={0};//访问每个位置,判断
int prime[100005]={0};//储存
int Prime(int x){
int n=0;
for(int i=2;i<=x;i++){
if(!visit[i])
prime[n++]=i;
for(int j=0;j<n&&i*prime[j]<=x;j++){
visit[i*prime[j]]=1;
if(i%prime[j]==0) break;//这个得细细琢磨,是这个方法的精髓!!!
}
}
return n; //记录找到了多少个素数(n为素数总数+1)
}
int main()
{
int x;
scanf("%d",&x);
int sum=Prime(x);
for(int i=0;i<sum;i++){
printf("%d ",prime[i]);
}
cout<<endl<<sum;
return 0;
}
这个方法中i*prime[j] 以及i%prime[j]==0这两步 可以通过打印出每一步的过程来帮助我们理解。比如:
我们可以看到,i在消去合数中的作用是:当做倍数来帮助代码找到合数并消去。
i%prime[j] == 0 break
:当 i是prime[j]的倍数时,i = k * prime[j](k>1),如果继续 j++,i * prime[j+1] = prime[j] * k *prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复此过程(变得麻烦且没必要),所以跳出循环。
5.判断是否为互质数/求两数最大公约数/最小公倍数
判断是否为质数:即求两个数的最大公约数(最后返回的b)是否为1
以下代码为求两数的最大公约数/最小公倍数,若为1则两数互质
辗转相除法:
int find(int a,int b){
int cmp;
// int aa=a,bb=b;
if(a<b){
cmp=a;
a=b;
b=cmp;
}
while(a%b){
cmp=b;
b=a%b;
a=cmp;
}
return b;//最大公约数
// return aa*bb/b;//最小公倍数:用两数的乘积除以两数的最大公约数
}
6.关于高精度
string对于高精度真的很友好,若不太懂请找找博客自行了解一下它的用法就好啦
高精度加法
noi:1.6 10大整数加法
题目中要考虑前导0
#include <bits/stdc++.h>
using namespace std;
string x,y;
int a[220],b[220],ans[220];
int main(){
cin>>x>>y;
int la=x.length();//string长度
int lb=y.length();
for(int i=0;i<la;i++){
a[la-i-1]=x[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i-1]=y[i]-'0';
}
int lc=max(la,lb);
for(int i=0;i<lc;i++){
ans[i]+=a[i]+b[i];
ans[i+1]=ans[i]/10;//如果>=10就进位
ans[i]%=10;//如果>=10就-10
}
if(ans[lc]) lc++;//考虑最高位是否存在进位
while(ans[lc-1]==0&&lc>1) lc--;//如果有前导0长度就减去,且考虑到如果都是0就保留最后一个0
for(int i=lc-1;i>=0;i--){
cout<<ans[i];
}
return 0;
}
高精度减法
#include <bits/stdc++.h>
using namespace std;
string x,y;
int a[220],b[220],ans[220];
int main(){
cin>>x>>y;
int la=x.length();
int lb=y.length();
if(la<lb || la==lb&&x<y){//string在两个长度相等的条件下可以自己通过字典序比较大小
swap(x,y);
swap(la,lb);
cout<<'-';
}
for(int i=0;i<la;i++){
a[la-i-1]=x[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i-1]=y[i]-'0';
}
int lc=max(la,lb);
for(int i=0;i<lc;i++){
if(a[i]<b[i]){
a[i]+=10;
a[i+1]--;
}
ans[i]=a[i]-b[i];
}
if(ans[lc]) lc++;
while(ans[lc-1]==0&&lc>1) lc--;
for(int i=lc-1;i>=0;i--){
cout<<ans[i];
}
return 0;
}
高精度乘法(A*B)
#include <bits/stdc++.h>
using namespace std;
string x,y;
int a[100010],b[100010],ans[100010];
int main(){
cin>>x>>y;
int la,lb,lc;
la=x.length();
lb=y.length();
lc=la+lb;
for(int i=0;i<la;i++){
a[la-i-1]=x[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i-1]=y[i]-'0';
}
for(int i=0;i<la;i++){
for(int j=0;j<lb;j++){
ans[i+j]+=a[i]*b[j];
ans[i+j+1]+=ans[i+j]/10;
ans[i+j]%=10;
}
}
while(ans[lc-1]==0&&lc>1) lc--;//去掉前导0
for(int i=lc-1;i>=0;i--){
cout<<ans[i];
}
return 0;
}
7.玩转二进制~(一些位运算的实用小技巧)
众所周知位运算可以让某些判断进行的更快~ 下面我们就来康康它的一些作用叭~
与
1.判断a的第i位为1/0:
a&(1<<i)
2.判断a是否为2的次方:
a&(a-1)//结果为0:是;结果为1:否
3.取a最低位上的1:
a&-a
举个栗子:
20(10)=10100(2)
20&-20=100(2)
4.将a的第i位变为0:
a&(0<<i)
或
1.将a的第i位变为1:
a|(1<<i)
2.求a的相反数:
~a+1
异或
1.将a的第i位取反:
a^(1<<i)
2.交换a b两个数的值:
a^b^b=a
或者
a^=b;
b^=a;
a^=b;