大概纲要
目录
1快速排序
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int a[N];
void qs(int a[], int l, int r){
if(l>=r) return ;
int i = l - 1,j=r+1,x=a[(l+r)>>1];
while(i<j){
do i++; while (a[i]<x);
do j--; while (a[j]>x);
if(i<j) swap(a[i],a[j]);
}
qs(a,l,j);
qs(a,j+1,r);
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i ++) scanf("%d",&a[i]);
qs(a,0,n-1);
for(int i = 0; i < n; i ++) printf("%d ", a[i]);
return 0;
}
为啥选取J,有证明可以证明,为i的话不能保证被正确划分,只有J才行。
2第k小数
用快速排序选择第k个,进行分治
通过长度和K比较再分治,
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int a[N];
int qs(int a[], int l, int r,int k){
if(l>=r) return a[l];
int i = l - 1,j=r+1,x=a[(l+r)>>1];
while(i<j){
do i++; while (a[i]<x);
do j--; while (a[j]>x);
if(i<j) swap(a[i],a[j]);
}
if(j - l + 1 >= k) return qs(a,l,j,k); //左边
else return qs(a, j+1, r, k - (j - l + 1)); //右边,变为第k - (j – l + 1)个
}
int main(){
int n,k;
scanf("%d %d", &n,&k);
for(int i = 0; i < n; i ++) scanf("%d",&a[i]);
cout<<qs(a,0,n-1,k);
return 0;
}
3归并排序:
结束:将区间二等分,当只有两个元素时,分了之后就直接返回了,然后将两个进行排序合并,依次递归回去。Tmp暂存,需要将值返回给原数组
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], tmp[N];
void merge_sort(int a[], int l, int r){
if(l >= r) return ;
int mid = l+r >> 1;
merge_sort(a,l,mid),merge_sort(a,mid+1,r);
int k = 0,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(i =l ,j=0;i<=r;i++,j++) a[i]=tmp[j];
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
merge_sort(a, 0, n - 1);
for (int i = 0; i < n; i ++ ) printf("%d ", a[i]);
return 0;
}
4求逆序对个数:
注意使用Long, long。
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], tmp[N];
long long ans=0;
void merge_sort(int a[], int l, int r){
if(l >= r) return ;
int mid = l+r >> 1;
merge_sort(a,l,mid), merge_sort(a,mid+1,r);
int k = 0,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else {
tmp[k++]=a[j++];
ans = ans + (mid - i + 1);
}
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(i =l,j=0;i<=r;i++,j++) a[i]=tmp[j];
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
merge_sort(a, 0, n - 1);
cout<<ans;
return 0;
}
5在数组中查找某元素,找不到就输出-1,找到了就输出不小于该元素的最小位置和不大于该元素的最大位置。
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int q[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
while (m -- )
{
int x;
scanf("%d", &x);
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
if (q[l] != x) cout << "-1 -1" << endl;
else
{
cout << l << ' ';
int l = 0, r = n - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (q[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}
1数的三次方根
给定一个浮点数 n,求它的三次方根。
#include<iostream>
using namespace std;
int main(){
double n;
cin>>n;
const double esp = 1e-8;
double l = -10000, r = 10000;
while( r - l >= esp){ //浮点数这样写
double mid = (l+r)/2;
if(mid*mid*mid>=n) r = mid;
else l = mid;
}
printf("%.6f",l);
return 0;
}
6前缀和:
#include<iostream>
using namespace std;
const int N = 1e5+10;
int a[N],sum[N];
int main(){
int n,m,x;
cin>>n>>m;
for(int i = 1;i<=n;i++){
cin>>x;
sum[i]=x+sum[i-1];
}
while(m--){
int l,r;
cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;
}
return 0;
}
7矩阵的子矩阵和:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1010;
int n,m,q;
int a[N][N],s[N][N];
int main()
{
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1]; //求前缀和
}
}
while(q--)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
}
return 0;
}
8差分 时间复杂度 o(m)
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i] - a[i - 1]; //构建差分数组
}
int l, r, c;
while (m--)
{
scanf("%d%d%d", &l, &r, &c);
b[l] += c; //将序列中[l, r]之间的每个数都加上c
b[r + 1] -= c;
}
for (int i = 1; i <= n; i++)
{
a[i] = b[i] + a[i - 1]; //前缀和运算
printf("%d ", a[i]);
}
return 0;
}
9二维矩阵差分:
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
int n, m, q;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
insert(i, j, i, j, a[i][j]); //构建差分数组
}
}
while (q--)
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; //二维前缀和
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
printf("%d ", b[i][j]);
}
printf("\n");
}
return 0;
}
10给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。 维护区间,移动的时候以右边那个为准,直到他的次数为一才行。
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], s[N];
int main()
{
int n, r = 0;
cin >> n;
for (int i = 0, j = 0; i < n; ++ i)
{
cin >> a[i];
++ s[a[i]];
while (s[a[i]] > 1) -- s[a[j++]]; // 先减次数后右移
r = max(r, i - j + 1) ;
}
cout << r;
return 0;
}
11给定两个升序排序的有序数组 A 和 B,以及一个目标值 x。
数组下标从 0 开始。
请你求出满足 A[i]+B[j]=x 的数对 (i,j)。
#include <iostream>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
int n ,m ,x;
scanf("%d%d%d", &n, &m, &x);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int j = 0; j < m; j ++ ) scanf("%d", &b[j]);
for (int i = 0, j = m - 1; a[i] < x; i ++ )
{
while(a[i] + b[j] > x) j --; // 重要的地方在这!
if (a[i] + b[j] == x)
{
printf("%d %d", i, j);
break;
}
}
return 0;
}
12判断子序列
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < n; i++) scanf("%d",&a[i]);
for(int j = 0;j < m; j++) scanf("%d",&b[j]);
int i = 0;
for(int j = 0;j < m; j++)
{
if(i < n&&a[i] == b[j]) i++;
}
if(i == n) puts("Yes");
else puts("No");
return 0;
}
13二进制中的一的个数
使用lowbit操作,进行,每次lowbit操作截取一个数字最后一个1后面的所有位,每次减去lowbit得到的数字,直到数字减到0,就得到了最终1的个数,
lowbit原理
根据计算机负数表示的特点,如一个数字原码是10001000,他的负数表示形势是补码,就是反码+1,反码是01110111,加一则是01111000,二者按位与得到了1000,就是我们想要的lowbit操作
C++ 代码
#include<iostream>
using namespace std;
int lowbit(int x){
return x&(-x);
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
int res=0;
while(x) x-=lowbit(x),res++;
cout<<res<<' ';
}
return 0;
}
暴力法:
#include<iostream>
using namespace std;
int n;
int a,k;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a);
k=0;
while(a){
k+=a&1;
a=a>>1;
}
printf("%d ",k);
}
return 0;
}
14离散化:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int a[N], s[N];
int n, m;
vector<int> alls;
vector<PII> add, query;
int find(int x)
{
int l = 0, r = alls.size() - 1;
while(l < r)
{
int mid = l + r >> 1;
if(alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1;
}
vector<int>:: iterator unique(vector<int> &a)
{
int j = 0;
for(int i = 0; i < a.size(); i ++)
if(!i || a[i] != a[i - 1])
a[j ++ ] = a[i];
return a.begin() + j;
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i ++ )
{
int x, c;
cin >> x >> c;
add.push_back({x, c});
alls.push_back(x);
}
for(int i = 0; i < m; i ++ )
{
int l, r;
cin >> l >> r;
query.push_back({l, r});
alls.push_back(l);
alls.push_back(r);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls), alls.end());
for(auto item : add)
{
int x = find(item.first);
a[x] += item.second;
}
for(int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];
for(auto item : query)
{
int l = find(item.first), r = find(item.second);
cout << s[r] - s[l - 1] << endl;
}
return 0;
}
15区间合并:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std ;
typedef pair<int,int> pii ;
vector<pii> nums,res ;
int main()
{
int st=-2e9,ed=-2e9 ; //ed代表区间结尾,st代表区间开头
int n ;
scanf("%d",&n) ;
while(n--)
{
int l,r ;
scanf("%d%d",&l,&r) ;
nums.push_back({l,r}) ;
}
sort(nums.begin(),nums.end()) ; //按左端点排序
for(auto num:nums)
{
if(ed<num.first) //情况1:两个区间无法合并
{
if(ed!=-2e9) res.push_back({st,ed}) ; //区间1放进res数组
st=num.first,ed=num.second ; //维护区间2
}
//情况2:两个区间可以合并,且区间1不包含区间2,区间2不包含区间1
else if(ed<num.second)
ed=num.second ; //区间合并
}
//(实际上也有情况3:区间1包含区间2,此时不需要任何操作,可以省略)
//注:排过序之后,不可能有区间2包含区间1
res.push_back({st,ed});
//考虑循环结束时的st,ed变量,此时的st,ed变量不需要继续维护,只需要放进res数组即可。
//因为这是最后的一个序列,所以不可能继续进行合并。
printf("%d",res.size()) ; //输出答案
return 0 ;
}
16高精度加减乘除
1高精度加法:
#include <iostream>
#include <vector>
using namespace std;
const int n =1e6 + 5;
vector<int> add(vector<int> &a,vector<int> &b){
vector<int> c;
int t=0;
for(int i=0; i<a.size() || i<b.size();i++){
if(i<a.size()) t+=a[i];
if(i<b.size()) t+=b[i];
c.push_back(t%10);
t=t/10;
}
if(t) c.push_back(1);
return c;
}
int main()
{
string a,b;
vector<int> A,B;
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--){
A.push_back(a[i]-'0');
}
for(int i=b.size()-1;i>=0;i--){
B.push_back(b[i]-'0');
}
auto c=add(A,B);
for(int i=c.size()-1;i>=0;i--){
printf("%d",c[i]);
}
return 0;
}
2高精度减法:
#include <iostream>
#include <vector>
using namespace std;
bool cmp(vector<int>& a, vector<int>& b)
{
if(a.size()!=b.size()) return a.size()>b.size();
for(int i=a.size()-1;i>=0;i--)
{
//最高位不相等
if(a[i]!=b[i]) return a[i]>b[i];
}
return true;
}
vector<int> sub(vector<int> &a,vector<int> &b){ //这里a是大于b的
vector<int> c;
for(int i=0,t=0;i<a.size();i++){
t=a[i]-t;
if(i<b.size()) t=t-b[i];
c.push_back((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(c.size()>1 && c.back() ==0) c.pop_back();
return c;
}
int main()
{
string a,b;
vector<int> A,B;
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--){
A.push_back(a[i]-'0');
}
for(int i=b.size()-1;i>=0;i--){
B.push_back(b[i]-'0');
}
if(cmp(A,B)){
auto c=sub(A,B);
for(int i=c.size()-1;i>=0;i--)
printf("%d",c[i]);
}
else
{
auto c=sub(B,A);
printf("-");
for(int i=c.size()-1;i>=0;i--)
printf("%d",c[i]);
}
return 0;
}
3高精度乘法
#include <iostream>
#include <vector>
using namespace std;
vector <int> mul(vector <int> & A, int b) {
vector <int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++) {
t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (t) {
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main() {
string a;
int b;
cin >> a >> b;
vector <int> A;
for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');
auto C = mul(A, b);
for (int i = C.size() - 1; i >= 0; i --) {
cout << C[i];
}
return 0;
}
4高精度除法
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> div(vector<int> &A,int b,int &r)
{
vector<int> C;
r=0;
for(int i=A.size()-1;i>=0;i--)
{
r=r*10+A[i];
C.push_back(r/b);
r%=b;
}
reverse(C.begin(),C.end());
while(C.size()>1 && C.back()==0) C.pop_back();
return C;
}
int main()
{
string a;
int b;
cin>>a>>b;
vector<int> A;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
int r;
auto C=div(A,b,r);
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
cout<<endl<<r<<endl;
return 0;
}