文章目录
1. 高精度
1.1 高精度加法
#include<iostream>
using namespace std;
int x[510],y[510],c[510],ans[510];
int main()
{
string a,b;
int i,j,lta,ltb;
cin>>a>>b;
int la=a.size();
int lb=b.size();
lta=la;//la在循环体里,不能在x[]中直接用
ltb=lb;
for(i=0;i<la;i++)
{
x[--lta]=a[i]-48;//字符转换成数字
}
for(i=0;i<lb;i++)
{
y[--ltb]=b[i]-48;
}
int len=max(la,lb);
for(i=0;i<=len;i++)//i<=len,否则会溢出
{
ans[i]=x[i]+y[i]+c[i];
if(ans[i]>9)
{
c[i+1]++;//进位
ans[i]-=10;
}
}
if(ans[len]!=0)
{
len++;//位数是否增加
}
for(j=len-1;j>=0;j--)
{
cout<<ans[j];
}
return 0;
}
1.2 高精度减法
#include<iostream>
#include<algorithm>
using namespace std;
int x[10090],y[10090],c[10090],ans[10090];
int main()
{
string a,b;
cin>>a>>b;
int i,la,lb,flag=0,len1,len2;
char op='-';
len1=a.size();
len2=b.size();
if(len1<len2||(len1==len2&&a<b))
{
flag=1;
swap(a,b);
swap(len1,len2);
}
la=len1;
lb=len2;
for(i=0;i<len1;i++)
{
x[--la]=a[i]-48;
}
for(i=0;i<len2;i++)
{
y[--lb]=b[i]-48;
}
for(i=0;i<len1;i++)
{
ans[i]=x[i]-y[i]-c[i];
if(ans[i]<0)
{
c[i+1]++;
ans[i]+=10;
}
}
while(len1>1&&ans[len1-1]==0)
len1--;
if(flag) cout<<op;
for(i=len1-1;i>=0;i--)
cout<<ans[i];
return 0;
}
1.3 高精度乘法
#include<iostream>
using namespace std;
int x[2010],y[2010],ans[4020];
int main()
{
string a,b;
int i,j;
cin>>a>>b;
int la=a.size();
int lb=b.size();
for(i=0;i<la;i++)
{
x[la-i-1]=a[i]-48;//字符转换成数字 ,逆序
}
for(i=0;i<lb;i++)
{
y[lb-i-1]=b[i]-48;
}
int len=la+lb-1;
for(i=0;i<la;i++)//i<=len,否则会溢出
{
for(j=0;j<lb;j++)
{
ans[i+j]+=x[i]*y[j];//若干个十次幂的和
}
}
for(i=0;i<len;i++)
{
if(ans[i]>9)
{
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
}
while(ans[len-1]==0&&len>1)
len--;
for(i=len-1;i>=0;i--)
{
cout<<ans[i];
}
return 0;
1.4 高精度除法
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
char a[5005];
int ans[5005];
int main()
{
long long b,k=0,c=0;
int la,i,top=0,flag=0;
cin>>a;
cin>>b;
la=strlen(a);
for(i=0;i<la;i++)
{
c=c*10+(a[i]-48);
if(c/b!=0) flag=1;
if(!flag) continue;
ans[top++]=c/b;
c=c%b;
}
for(i=0;i<top;i++)
{
cout<<ans[i];
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int a[5005],b[100],c[5005],ans[5005];
bool cmp();
int main()
{
string x,y;
int i,j,k;
cin>>x>>y;
a[0]=x.size();
b[0]=y.size();//a[0]b[0]c[0]均用于记录位数
for(i=1;i<=a[0];i++)
{
a[i]=x[a[0]-i]-48;
}
for(i=1;i<=b[0];i++)
{
b[i]=y[b[0]-i]-48;//逆序
}
c[0]=0;
for(i=a[0];i>=1;i--)
{
for(j=b[0];j>=1;j--)
{
c[j+1]=c[j];//数字右移,相当于乘上十次幂
}
c[1]=a[i];
c[0]++;if(!c[c[0]])--c[0];
while(cmp())
{
int t=0;
for(k=1;k<=c[0];k++)
{
c[k]=c[k]-b[k]-t;
if(c[k]<0)
{
c[k]+=10;
t=1;
}
else t=0;
}
while(c[0]>1&&c[c[0]]==0)
{
c[0]--;//去除余数的前导0
}
ans[i]++;//每从c中减去一个b,当前位答案计数加1
}
}
ans[0]=a[0];
while(ans[0]>1&&ans[ans[0]]==0)
ans[0]--;//去除答案前导0
for(i=ans[0];i>=1;i--)
cout<<ans[i];
return 0;
}
bool cmp()//比较余数与除数的大小
{
if(b[0]>c[0])
return 0;
if(b[0]<c[0])
return 1;
for(int i=c[0];i>=1;i--)
{
if(c[i]<b[i])
return 0;
else if(c[i]>b[i])
return 1;
}
return 1;
}
2. 排序
2.1 冒泡排序
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n-1;j++)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1];
}
}
2.2 选择排序
for(int i=1;i<=n;i++)
{
int m=i;
for(int j=i+1;j<=n;j++)
{
if(a[j]<a[m])
{
m=j;
swap(a[m],a[j]);
}
}
}
2.3 插入排序
for(int i=2;i<=n;i++)
{
if(a[i]<a[i-1])
{
int m=a[i];
for(int j=i-1;j>=1&&a[j]>m;j--)
a[j+1]=a[j];
a[j+1]=m;
}
}
2.4 归并排序
求逆序对
归并排序,每次将左右两边合并时,左边、右边的内部次序都已经排好,但是左右各个数据之间的大小关系不确定。合并时每次比较左右两边排在最先的数据,如果该数据在右边,表明左边当前与右边的该数据进行比较的数据及左边之后的数据都比右边的该数据大,这些数据的个数要算在逆序对上。
#include<bits/stdc++.h>
using namespace std;
int temp[500005],a[500005],n;
long long ans;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void merge(int l,int r)
{
if(l==r) return;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
int i=l,j=mid+1,p=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
temp[p++]=a[i++];
else
ans+=(mid-i+1),//计算逆序数
temp[p++]=a[j++];
}
while(i<=mid)
temp[p++]=a[i++];
while(j<=r)
temp[p++]=a[j++];
for(int k=l;k<=r;k++)
a[k]=temp[k];
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
merge(1,n);
cout<<ans;
return 0;
}
2.5 快速排序
#include<bits/stdc++.h>
using namespace std;
int a[1000001],N;
void qsort(int l,int r)
{
if(l>=r) return;
else
{
int i=l;
int j=r;
int t=a[rand()%(r-l+1)+l];
while(a[i]<t) i++;
while(a[j]>t) j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;
j--;
}
qsort(l,j);
qsort(i,r);
}
}
int main()
{
int i;
cin>>N;
for(i=1;i<=N;i++)
{
cin>>a[i];
}
srand(int(time(0)));
qsort(1,N);
for(i=1;i<=N;i++)
cout<<a[i]<<' ';
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int a[1001],N;
void print(int *arr)
{
for(int i=1;i<=N;i++)
printf("%d ",arr[i]);
cout<<endl;
}
void qsort(int l,int r)
{
if(l>=r) return;
else
{
int i=l;
int j=r;
int t=a[l];
while(i<j)
{
while(i<j&&a[j]>t)
j--;
while(i<j&&a[i]<=t)
i++;
swap(a[i],a[j]);
}
swap(a[i],a[l]);
print(a);
qsort(l,i-1);
qsort(i+1,r);
}
}
int main()
{
int i;
cin>>N;
for(i=1;i<=N;i++)
cin>>a[i];
qsort(1,N);
print(a);
return 0;
}
求第k小的数
快排的原理就是每次确定一个数在整个序列中的位次,每排完一轮之后该数左边的数都比它小,右边的数都比它大。当我们不断缩小范围找到第k个位次之后,快排一轮将相应的数交换过来即可。
#include<bits/stdc++.h>
using namespace std;
int x[5000005],k;
void qsort(int l,int r)
{
int i=l,j=r,mid=x[(l+r)/2];//mid可以是随机产生的数
while(i<=j)
{
while(x[j]>mid) j--;
while(x[i]<mid) i++;
if(i<=j)
{
swap(x[i],x[j]);
i++;
j--;
}
}
if(k<=j) qsort(l,j);
else if(i<=k) qsort(i,r);
else
{
printf("%d",x[j+1]);
exit(0);
}
}
int main()
{
int n;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
qsort(0,n-1);
}
2.6 堆排序
先放STL版本的,暂时不会手写堆排序。
建堆:make_heap(first,last,cmp);
make_heap(vec.begin(),vec.end(),cmp);
cmp: 大顶堆:less<int();小顶堆:greater<int().
增加元素:push_heap(vec.begin(),vec.end(),x);
删除元素:pop_heap(vec.begin(),vec.end(),x);
(堆顶元素放到了vec的末尾,可以用pop_back()删除)
堆排序:sort_heap(vec.begin(),vec.end(),cmp);
第三个参数需与建堆的一致。
3. 数论
3.1 质数
3.1.1 埃氏筛法
void prime(int n)
{
memset(v,0,sizeof(v));//合数标记
for(int i=2;i<=n;i++)
{
if(v[i])continue;
//cout<<i<<endl;
for(int j=i;j<=n/i;j++)
v[i*j]=1;
}
}
3.1.2 欧拉筛法
int v[N],prime[N];
void primes(int n)
{
memset(v,0,sizeof(v));//最小质因子
m=0;//质数数量
for(int i=2;i<=n;i++)
{
if(v[i]==0)
v[i]=i,prime[++m]=i;//i是质数
//给当前的数i乘上一个质因子
for(int j=1;j<=m;j++)
{
if(prime[j]>v[i]||prime[j]>n/i) break;
//i有比prime[j]更小的质因子,或者超出n的范围,停止循环
v[i*prime[j]]=prime[j];
//prime[j]是合数i*prime[j]的最小质因子
}
}
}
3.1.3 质因数分解
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;
cout << i << ' ' << s << endl;
}
if (x > 1) cout << x << ' ' << 1 << endl;
cout << endl;
}
3.2 约数
约数个数和约数之和
如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)
3.2.1 求所有约数
vector<int> get_divisors(int x)
{
vector<int> res;
for (int i = 1; i <= x / i; i ++ )
if (x % i == 0)
{
res.push_back(i);
if (i != x / i) res.push_back(x / i);
}
sort(res.begin(), res.end());
return res;
}
3.2.2 欧几里得算法
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
3.3 欧拉函数
欧拉函数:1~N中与N互质的数的个数。
#include<bits/stdc++.h>
using namespace std;
int n;
int euler(int x)
{
int ans=x;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
ans=ans/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) ans=ans/x*(x-1);
return ans;
}
int main()
{
cin>>n;
while(n--)
{
int x;
cin>>x;
cout<<euler(x)<<endl;
}
return 0;
}
筛法求欧拉函数:
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,cnt;
int primes[N],v[N],ans[N];
long long total;
int euler(int n)
{
ans[1]=1;
total++;
for(int i=2;i<=n;i++)
{
if(!v[i])
{
primes[++cnt]=i;
ans[i]=i-1;
}
for(int j=1;primes[j]*i<=n;j++)
{
int t=primes[j]*i;
v[t]=1;
if(i%primes[j]==0)
{
ans[t]=ans[i]*primes[j];
break;
}
else ans[t]=ans[i]*(primes[j]-1);
}
total+=ans[i];
}
}
int main()
{
cin>>n;
euler(n);
cout<<total;
return 0;
}
3.4 快速幂
ll ksc(ll x,ll y)
{
ll ans=0;
while(y)
{
if(y&1) ans=(ans+x)%mod;
x=2*x%mod;
y/=2;
}
return ans;
}
long long ksm(long long base,long long power)
{
base%=mod;
long long ans=1;
while(power)
{
if(power&1)
ans=ans*base%mod;
power>>=1;
base=base*base%mod;
}
return ans;
}
快速幂求逆元:
#include<iostream>
using namespace std;
long long qmi(long long a,int b,int p)
{
long long res=1;
while(b)
{
if(b&1) res = res *a %p;
b>>=1;
a=a*a%p;
}
return res;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a,p;
scanf("%d%d",&a,&p);
long long res=1;
if(a%p==0) cout<<"impossible"<<endl;
else cout<<qmi(a,p-2,p)<<endl;
}
return 0;
}
3.5 同余
3.5.1 扩展欧几里得算法
#include<bits/stdc++.h>
using namespace std;
int n;
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int main()
{
cin>>n;
while(n--)
{
int a,b,x,y;
scanf("%d%d",&a,&b);
exgcd(a,b,x,y);
printf("%d %d\n",x,y);
}
}
3.5.2 线性同余方程
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int main()
{
cin>>n;
while(n--)
{
int a,b,x,y,m;
scanf("%d%d%d",&a,&b,&m);
int t=exgcd(a,m,x,y);
if(b%t) printf("impossible\n");
else printf("%d\n",(LL)b/t*x%m);
}
}
3.5.3 中国剩余定理
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
LL a1,m1,x=0;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int n;
cin>>n;
cin>>a1>>m1;
for(int i=1;i<n;i++)
{
LL a2,m2,k1,k2;
cin>>a2>>m2;
LL d=exgcd(a1, a2, k1, k2);
if ((m2-m1)%d)
{
x=-1;
break;
}
k1*=(m2-m1)/d;
k1=(k1%(a2/d)+a2/d)%(a2/d);
x=k1*a1+m1;
LL a=abs(a1/d*a2);
m1=k1*a1+m1;
a1 = a;
}
if(x!=-1) x=(m1%a1+a1)%a1;
cout<<x;
return 0;
}
3.6 高斯消元
#include<bits/stdc++.h>
using namespace std;
int n;
double a[110][110],eps=1e-8;
int gauss()
{
int r,c;
for(c=0,r=0;c<n;c++)
{
int t=r;
for(int i=r;i<n;i++)
if(fabs(a[i][c])>fabs(a[t][c]))
t=i;
if(fabs(a[t][c])<eps) continue;
for(int i=c;i<=n;i++) swap(a[r][i],a[t][i]);
for(int i=n;i>=c;i--) a[r][i]/=a[r][c];
for(int i=r+1;i<n;i++)
if(fabs(a[i][c])>eps)
for(int j=n;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c];
r++;
}
if(r<n)
{
for(int i=r;i<n;i++)
if(fabs(a[i][n])>eps)
return 2;
return 1;
}
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
a[i][n]-=a[i][j]*a[j][n];
return 0;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
cin>>a[i][j];
int t=gauss();
if (t == 2) puts("No solution");
else if (t == 1) puts("Infinite group solutions");
else
{
for (int i=0;i<n;i++)
{
if(fabs(a[i][n])<eps) a[i][n]=0;
printf("%.2lf\n", a[i][n]);
}
}
}
3.7 组合计数
3.7.1 求组合数的几种方式
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,c[2010][2010];
void init()
{
for(int i=0;i<=2000;i++)
for(int j=0;j<=i;j++)
if(j==0) c[i][j]=1;
else c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
int main()
{
cin>>n;
init();
while(n--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",c[a][b]);
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=1e9+7;
typedef long long LL;
int n;
LL fact[N],infact[N];
LL qmi(int x,int y)
{
LL ans=1;
while(y)
{
if(y&1) ans=(LL)ans*x%mod;
y>>=1;
x=(LL)x*x%mod;
}
return ans;
}
void init()
{
fact[0]=infact[0]=1;
for(int i=1;i<N;i++)
{
fact[i]=fact[i-1]*i%mod;
infact[i]=(infact[i-1]*qmi(i,mod-2))%mod;
}
}
int main()
{
cin>>n;
init();
while(n--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",fact[a]*infact[b]%mod*infact[a-b]%mod);
}
}
#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=1e9+7;
typedef long long LL;
int n;
LL fact[N],infact[N];
LL qmi(int x,int y,int p)
{
LL ans=1;
while(y)
{
if(y&1) ans=(LL)ans*x%p;
y>>=1;
x=(LL)x*x%p;
}
return ans;
}
LL C(int a,int b,int p)
{
if(b>a) return 0;
LL ans=1;
for(int i=1,j=a;i<=b;i++,j--)
{
ans=ans*j%p;
ans=ans*qmi(i,p-2,p)%p;
}
return ans;
}
LL lucas(LL a,LL b,int p)
{
if(a<p&&b<p) return C(a,b,p);
else return C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;
}
int main()
{
cin>>n;
while(n--)
{
LL a,b;
int p;
cin>>a>>b>>p;
cout<<lucas(a,b,p)<<endl;
}
}
3.7.2 卡特兰数
C
a
t
(
n
)
=
C
2
n
n
/
(
n
+
1
)
Cat(n) = C_{2n}^{n} / (n + 1)
Cat(n)=C2nn/(n+1)
#include<bits/stdc++.h>
using namespace std;
const int p=1e9+7;
typedef long long LL;
LL qmi(int x,int y)
{
LL ans=1;
while(y)
{
if(y&1) ans=(LL)ans*x%p;
y>>=1;
x=(LL)x*x%p;
}
return ans;
}
LL C(int a,int b)
{
if(b>a) return 0;
LL ans=1;
for(int i=1,j=a;i<=b;i++,j--)
{
ans=ans*j%p;
ans=ans*qmi(i,p-2)%p;
}
return ans;
}
int main()
{
int n;
cin>>n;
int a=2*n,b=n;
cout<<C(a,b)*qmi(n+1,p-2)%p<<endl;
}