写在前面 :一些经常忘记的知识
sort(begin,end)
一般是升序sort(a,a+n) a是数组名,n是数组长度
降序的时候用#include<functional>
sort(a,a+n,greater<int>());
强制转换数据类型是 (double) x !!!!
也可以x * 1.0
普通输入挂怎么写
#include<cstdio>;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int main(){
int n=read();
printf("%d",n);
return 0;
}
int n;
while(scanf("%d",&n)!=EOF);
while(cin>>n);这个对于未指定个数的输入有用
printf常考
1. %3d 表示输出3位整型数, 不够3位右对齐。 %03d 表示输出3位整型数, 不够3位前面用0补齐。
2. %9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,double类型的lf也一样
3. %-7d 表示输出7位整数左对齐 这个-就是左对齐
4. %d int %ld long %lld long long
#include<bitset>
cout<<(bitset<5>)n; 将n转换成长度为5的二进制串
#include<string>中string常用函数
string s='i can see you.';
char s1[10];
1. s可以用下标的方式输出 下标从0开始,s[0]=i;
2. 输入字符串有空格就用getline(cin,s),另外用scanf("%[^\n}",s1)
3. s.size()和s.length()可以求字符串长度
4. s.substr(begin,len)可以取出字串从begin位置开始取出长度为len的字串
#include<vector> 动态数组
vector <int> v; 创建一个vector v
int a[10]; vector <int> v2(a,a+10);
vector<int>v3(10,1); vector中有10个类型为int的1
v.push_back(10); 把10加入v的最后面
v.pop_back(); 从后取数
int x=v[0]; v可以用下标的方式取数
vector查找用find函数需要加上头文件
#include<algorithm>
vector <int>::iterator it=find(v.begin(),v.end(),x)
if(it==v.end())//没找到
海伦公式
int a,b,c;
cin>>a>>b>>c;
int p=(a+b+c)/2;
int s=sqrt(p*(p-a)*(p-b)*(p-c));
卡特兰数
可以看https://www.bilibili.com/video/BV1nE411A7ST
up讲的很清楚
//卡特兰数 n个节点可以构成几种二叉树
//f(n)=f(0)*f(n-1)+f(1)*f(n-2)+...+f(n-1)*f(0)
#include<iostream>
using namespace std;
long long f[20]={1};//f(0)=1;0个节点可以构成空树
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
f[i]+=f[j]*f[i-1-j];
}
}
cout<<f[n];
return 0;
}
STL二分查找
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
/*
upper_bound返回第一个大于所查找值的指针--相当于右侧二分+1
要转化成下标就是 r-a
lower _bound返回第一个大于等于所查找值的指针 相当于左侧二分
如果找不到的话,则两个函数返回值一样
找得到的话,值不同
x 1 2 4 8
u 1 4 7 8
l 0 1 7 8
*/
int main(){
int a[]={1,2,2,2,3,3,3,7};
int *r1=upper_bound(a,a+8,1);
int *l1=lower_bound(a,a+8,1);
cout<<r1-a<<' '<<l1-a<<endl;
int *r2=upper_bound(a,a+8,2);
int *l2=lower_bound(a,a+8,2);
cout<<r2-a<<' '<<l2-a<<endl;
int *r3=upper_bound(a,a+8,4);
int *l3=lower_bound(a,a+8,4);
cout<<r3-a<<' '<<l3-a<<endl;
int *r4=upper_bound(a,a+8,8);
int *l4=lower_bound(a,a+8,8);
cout<<r4-a<<' '<<l4-a<<endl;
return 0;
}
二分查找
有三种二分(经典二分,左侧二分-查找第一个出现的数,右侧二分查找最后一个出现的数)
#include<cstdio>
#include<iostream>
#include<algorithm>
int a[1000];
using namespace std;
int check_left(int x,int low,int high){
int l=low,r=high;
while(l<=r){
int mid=l+(r-l)/2;
if(x==a[mid])r=mid-1;
else if(x<a[mid])r=mid-1;
else l=mid+1;
}
if(l>high||a[l]!=x) return -1;
return l;
}
int check_right(int x,int low,int high){
int l=low,r=high;
while(l<=r){
int mid=l+(r-l)/2;
if(x>=a[mid])l=mid+1;
else if(x<a[mid])r=mid-1;
}
if(r<low||a[r]!=x) return -1;
return r;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int x=2;
cout<<check_right(x,0,n-1);
return 0;
}
下面的写的有问题
//经典二分
while(low<=high){//注意!!!
mid=low+(high-low);/2//防止溢出
if(a[mid]==x)return mid;//重点
else if(a[mid]>x) high=mid-1;
else low=mid+1;
}
return -1;
//左侧二分
while(low<=high){
mid=low+(high-low);/2//防止溢出
if(a[mid]==x)return high=mid-1;//应该向左侧靠,缩小右边边界
else if(a[mid]>x) high=mid-1;
else low=mid+1;
}
if(left>n||a[left]!=x) return -1;//查找不到返回-1
return low;//返回左边的下标
欧拉函数
//欧拉函数 判断一个数与(1,n)之间的整数互质的个数
//公式法
#include<iostream>
using namespace std;
int oula(int n){
int ans=n;
//这里是质因式分解
for(int i=2;i*i<=n;i++){
if(n%i==0){
//只要余数得0,则一定是质因数,套用公式
ans=ans/i*(i-1);
while(n%i==0){
n/=i;
}
}
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
int main(){
int n;
cin>>n;
cout<<oula(n);
return 0;
}
欧拉筛
//欧拉筛
#include<iostream>
using namespace std;
const int N=10000;
//phi[i]=x表示在1-i中与i互质的个数有x个
//prime表示质数个数
int phi[N],prime[N];
//标记i是否为质数,是合数就置0
bool flag[N];
void EulerFilter(int n){
phi[1]=1;
int count=0;
for(int i=2;i<=n;i++){
if(flag[i]==0){
prime[++count]=i;
//如果i是质数,利用欧拉函数的性质
//质数的欧拉函数值等于质数-1
phi[i]=i-1;
}
//欧拉筛是i的所有质数倍
//素数筛是质数的所有i倍
for(int j=1;j<=count&&i*prime[j]<=n;j++){
flag[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
}
else{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
int main(){
int n;
cin>>n;
EulerFilter(n);
for(int i=1;i<=n;i++)
cout<<phi[i]<<' ';
return 0;
}
素数筛
//素数筛
#include<iostream>
using namespace std;
const int N=10000;
bool flag[N];
int main(){
int n;
cin>>n;
flag[1]=1;
int count=0;
for(int i=2;i<=n;i++){
if(flag[i]==0){
for(int j=2;i*j<=n;j++){
flag[i*j]=1;
}
count++;
}
}
cout<<count;
return 0;
}
质因式分解
//这种是容易理解的方法
//分解质因式,分解从1-n的质因式
//表达形式为8=2*2*2
#include<iostream>
using namespace std;
int IsPrime(int x){
if(x==1)return 0;
for(int i=2;i*i<=x;i++){
if(x%i==0)return 0;
}
return 1;
}
int main(){
int n,i,j,temp;
cin>>n;
for(i=1;i<=n;i++){
temp=i;
if(IsPrime(temp)||temp==1){cout<<temp<<"="<<temp<<endl;continue;}
cout<<temp<<"=";
for(j=2;j<temp;j++){//注意这里式<temp temp的质因子只能
//是在2-temp-1之间,而且temp的值在变
if(IsPrime(j)){
while(temp%j==0){
temp/=j;
cout<<j<<"*";
//如果temp被除的只剩下一个质数
if(IsPrime(temp)){
cout<<temp;
goto end;
}
}
}
}
end:cout<<endl;
}
return 0;
}
//分解质因数 输出N的质因数的个数。
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
int count=0;
//不用判断是否是质数
for(int i=2;i*i<=n;i++){
if(n%i==0){
while(n%i==0){
n/=i;
count++;
}
}
}
if(n>1)count++;
cout<<count;
return 0;
}
高精度
//核心
for(i=1;i<lc;i++)
{
c[i]+=a[i]+b[i];
c[i+1]=c[i]/10;
c[i]%=10;
}
for(i=1;i<=la;i++)
{
for(j=1;j<=lb;j++)
{
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/10;
c[i+j-1]%=10;
}
}
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<stdio.h>
#include<string.h>
using namespace std;
void High_precisionaddition()
{
string s1,s2;
cin>>s1>>s2;
int a[100]={0},b[100]={0},c[1000]={0},i,la,lb,lc;
la=s1.size();
lb=s2.size();
//lc=la+lb;和乘法搞混了
lc=max(la,lb)+1;//注意这个lc不一定是最后和的长度,还要判断前导零
for(i=la-1;i>=0;i--)
a[la-i]=s1[i]-'0';
for(i=lb-1;i>=0;i--)
b[lb-i]=s2[i]-'0';//注意这里是从1开始存储
for(i=1;i<lc;i++)
{
c[i]+=a[i]+b[i];
c[i+1]=c[i]/10;
c[i]%=10;
}
//高位低位一直没搞清楚
//一开始string把高位存在0处,用一个数组把地位存在1处好进行计算
//输出的时候应该先输出高位,但是要先判断是否有前导零,就是c[lc]的地方是否为0
//还要注意 0+0的情况
for(i=1;i<=lc;i++)
{
if(c[i]!=0)break;
if(i==lc)
{
cout<<0;
return;
}
}
for(int i=lc;i>=1;i--)
{
if(c[i]==0&&i==lc)continue;
cout<<c[i];
}
}
void High_precisionmultiplication()
{
string s1,s2;
cin>>s1>>s2;
int a[100]={0},b[100]={0},i,j,la,lb,lc;
//对于一些要求位数很大的题,可以用malloc分配内存
int* const c=(int*)malloc(sizeof(int)*100000);
memset(c,0,sizeof(c)*100000);
la=s1.size();
lb=s2.size();
lc=la+lb;
for(i=la-1;i>=0;i--)
a[la-i]=s1[i]-'0';
for(i=lb-1;i>=0;i--)
b[lb-i]=s2[i]-'0';//注意这里是从1开始存储
//这里是个二重循环
for(i=1;i<=la;i++)
{
for(j=1;j<=lb;j++)
{
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/10;
c[i+j-1]%=10;
}
}
for(i=lc;i>0;i--)
{
if(c[i]!=0)break;
}
for(j=i;j>0;j--)
cout<<c[j];
}
int main()
{
//High_precisionaddition();
High_precisionmultiplication();
return 0;
}
gcd和lcm
编写一函数gcd,求两个正整数的最大公约数和最小公倍数
总结:
用辗转相除(欧几里得)来求gcd,lcm就是两数乘积除以gcd得出的商
(辗转相除就是我们初高中学的,但是那时候我只知道该怎么做,不懂为啥那么做,下面是我结合一些网上的求证写出的证明思路)
(枚举就不说了)
多数就是先求出两个数的gcd,再用gcd与另一个数求出gcd
int gcd(int[] a,int n) {//a保存了数,n是数组长度
int g = a[0];
for(int i=1;i<n;i++)
g = gcd(g,a[i]);
return g;
}
int lcm(int[] a,int n) {
int l = a[0];
for(int i=1;i<n;i++)
l = lcm(l,a[i]);
return l;
}
int gcd(int a,int b)//注意a>b
{
int r=a%b;
if(!r)return b;
gcd(b,r);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
1)Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现 在,刚刚放学回家的Hankson 正在思考一个有趣的问题。 今天在课堂上,老师讲解了如何求两个正整数c1 和c2 的最大公约数和最小公倍数。现 在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公 倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整 数x 满足: 1. x 和a0 的最大公约数是a1; 2. x 和b0 的最小公倍数是b1。 Hankson 的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x 的个数。请你帮 助他编程求解这个问题。
【输入形式】
输入第一行为一个正整数n,表示有n 组输入数据。
接下来的n 行每 行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入 数据保证a0 能被a1 整除,b1 能被b0 整除。
数据规模和约定
对于 50%的数据,保证有1≤a0,a1,b0,b1≤10000 且n≤100。
对于 100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000 且n≤2000。
【输出形式】
输出共n 行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 x,请输出0; 若存在这样的 x,请输出满足条件的x 的个数;
【样例输入】
2
41 1 96 288
95 1 37 1776
【样例输出】
6
2
【提示】
样例说明
第一组输入数据,x 可以是9、18、36、72、144、288,共有6 个。
第二组输入数据,x 可以是48、1776,共有2 个。
(实在数学不好,直接公式暴力只能得一半分,等我研究清楚了再写)
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
int gcd(int a,int b)//注意a>b
{
int t=a;
if(t<b)
{
t=b;
b=a;
a=t;
}
int r=a%b;
if(!r)return b;
gcd(b,r);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
int main()
{
int n,a0,a1,b0,b1,x,c=0;
cin>>n;
while(n--)
{
c=0;
//cout<<'dhf';
cin>>a0>>a1>>b0>>b1;
for(x=a1;x<=b1;x+=a1)//a1整除x
{
if(gcd(x,a0)==a1&&lcm(x,b0)==b1)
c++;
}
cout<<c<<endl;
}
return 0;
}
快速幂
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<stdio.h>
#include<string.h>
using namespace std;
int qpow()
{
int a,m;//a^m
cin>>a>>m;
int prod=1;//连乘器
while(m>0)
{
if(m&1)
prod=prod*a;
a*=a;
m>>=1;
}
cout<<prod;
return prod;
}
int main()
{
qpow();
return 0;
}