# [AcWing algorithm basic course] Week1 exercise course

#### AcWing 786 number k

1. Use quick sort for the whole array, and then directly output the k-th number sorted from small to large. The time complexity is O(nlogn)

```#include <iostream>
using namespace std;

const int N=100000;
int n;
int k;
int q[N];

void quick_sort(int q[],int l,int r){
if(l>=r) return;
int x=q[(l+r)/2],i=l-1,j=r+1;
while(i<j){
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
quick_sort(q,l,j);
quick_sort(q,j+1,r);
return;
}

int main(){
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&q[i]);
}
quick_sort(q,0,n-1);
printf("%d",q[k-1]);
return 0;
}
```

2. Fast selection algorithm

Only the interval on one side of recursion is needed each time, and the time complexity is O(n)

1. Find the dividing point, which can be q[L], q[(L+R)/2], q[R] or a random array element
2. Adjust the range and select x (x is a value) so that all numbers in the first interval (Left) are less than or equal to X and all numbers in the second interval (Right) are greater than or equal to X
3. Count the number of all elements on the Left s l s_l sl​
4. Judge k and s l s_l Size of sl
If K<= s l s_l sl, then the k-th smallest number must be in Left. We only need to deal with Left recursively, not Right
If k > s l s_l sl, then the k-th smallest number must be in Right. We only need to deal with Right recursively, not Left
5.k represents the k-th smallest number in the whole interval from l to r, then we subtract all the small numbers in Left to obtain the k-th smallest number in the Right half interval, that is, K- s l s_l sl​
```#include <iostream>
using namespace std;

const int N=100010;
int n,k;
int q[N];

int quick_choose(int q[],int l,int r,int k){
if(l>=r) return q[l];
int x=q[(l+r)/2],i=l-1,j=r+1;
while(i<j){
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
int sl=j-l+1;
if(k<=sl){
quick_choose(q,l,j,k);
}else{
quick_choose(q,j+1,r,k-sl);
}
}

int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
int res=quick_choose(q,0,n-1,k);
cout<<res<<endl;
return 0;
}
```

#### AcWing 788. Number of pairs in reverse order

We divide all pairs in reverse order into three categories:

1. Both numbers appear on the left side at the same time
2. Both numbers appear on the right half at the same time
3. One appears on the left half and one appears on the right half

The meaning we give to the recursive function is to find the number of all inverse pairs in the interval while merging and sorting

Then the number of reverse pairs in the whole interval [L,R] is: merge(Left)+merge(Right) + the number of reverse pairs on the left and right sides

There are two pointers I, j, Q [i] > Q [j]
Because Left and Right are ordered, all elements from i to mid are greater than q[j], while all elements before i are less than q[j]

1. Partition interval [L,R] – > [l, mid] and [mid+1,R]
2. Recursively handle [L,mid] and [mid+1,R]
3. Merge to find the number of reverse pairs on the left and right sides
```#include <iostream>
using namespace std;
typedef long long LL;

int n;
const int N=100010;
int q[N],temp[N];

LL merge(int q[],int l,int r){
if(l>=r) return 0;
LL res=0;
int mid=(l+r)>>1;
res=merge(q,l,mid)+merge(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r){
if(q[i]<=q[j]) temp[k++]=q[i++];
else{
res+=mid-i+1;
temp[k++]=q[j++];
}
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
return res;
}

int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
cout<<merge(q,0,n-1)<<endl;
return 0;
}
```

Find the number of reverse pairs in the array. On the force buckle, it is the sword finger Offer 51. Reverse pairs in the array

#### AcWing 790. The cubic root of a number

```#include <iostream>
using namespace std;
double n;

int main(){
cin>>n;
double l=-10000,r=10000;
while(r-l>1e-8){
double mid=(l+r)/2;
if(mid*mid*mid>=n) r=mid;
else l=mid;
}
printf("%lf\n",l);
return 0;
}
```

#### AcWing 795. Prefix and

This problem has been done before. The code is as follows

```#include <iostream>
using namespace std;
int n,m;
const int N=100010;
int q[N],s[N];

int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&q[i]);
s[0]=0;
for(int i=1;i<=n;i++) s[i]=s[i-1]+q[i];
while(m--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",s[r]-s[l-1]);
}
return 0;
}
```

#### AcWing 796. Sum of submatrixes

Expand from one-dimensional prefix and to two-dimensional prefix and.

We specify that i is a row and j is a column

s i j s_{ij} sij ， means the sum of all numbers in the upper left corner of (i,j). for example s 34 s_{34} s34 is the sum of all numbers in the green part of the figure.

Consider two questions:

1. s i j s_{ij} sij# how to calculate?
2. Given a submatrix with point (x1,y1) as the upper left corner and point (x2,y2) as the lower left corner, how to calculate the sum of all numbers in the submatrix?

The formula of question 2 is: s[ x 2 x_2 x2​, y 2 y_2 y2​]-s[ x 1 − 1 x_{_1-1} x1​−1​, y 2 y_2 y2​]-s[ x 2 x_2 x2​, y 1 − 1 y_{_1-1} y1​−1​]+s[ x 1 − 1 x_{_1-1} x1​−1​, y 1 − 1 y_{_1-1} y1​−1​]

Question 1 how s i j s_{ij} The formula of sij is: s[i,j]=s[i-1,j]+s[i,j-1]-s[i-1,j-1]+a[i,j]

```#include <iostream>
using namespace std;
const int N=1010;
int n,m,q;
//a is the original array and s is the prefix and array
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]);
}
}
//Initializing prefixes and arrays
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]-s[i-1][j-1]+a[i][j];
}
}
//inquiry
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;
}
```

#### AcWing 797. Differential

The same is a written question.

```#include <iostream>
using namespace std;
const int N=100010;
int n,m;
int a[N],b[N];

void insert(int l,int r,int c){
b[l]+=c;
b[r+1]-=c;
}

int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) insert(i,i,a[i]);
while(m--){
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);
}
for(int i=1;i<=n;i++) a[i]=a[i-1]+b[i];
for(int i=1;i<=n;i++) printf("%d ",a[i]);
return 0;
}
```

#### AcWing 798. Difference matrix

Extended to two-dimensional difference.

Given the original matrix a[i,j], the difference matrix b[i,j] is constructed so that a [] [] is the two-dimensional prefix and sum of b [] [].

We assume that a [] [] is all 0, and b [] [] is all 0. We just need to build a [] [] Based on the core operation.

Core operation: add C to all the numbers (a[i][j] in the original array) in the submatrix with (x1,y1) as the upper left corner and (x2,y2) as the lower right corner

Impact on the difference group:

• b[x1][y1]+=c
• b[x1][y2+1]-=c
• b[x2+1][y1]-=c
• b[x2+1][y2+1]+=c

Because a [] [] is the prefix sum of b [] [] and the two-dimensional prefix sum is the sum of all numbers in the upper left corner, b[x1][y1]+=c will add C to all numbers in the upper left corner and lower right corner with (x1,y1) (that is, all green parts in the figure below)

The prefix sum of all green dots includes (x1,y1), so after b[x1][y1]+=c, all green dots are also added with C

We imagine a [] [] as all 0, and then add a[i][j] to the matrix with (i,j) as the upper left corner and (i,j) as the lower right corner.

```#include <iostream>
using namespace std;
const int N=1010;
int n,m,q;
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(){
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++)
insert(i,j,i,j,a[i][j]);
while(q--){
int x1,y1,x2,y2,c;
scanf("%d%d%d%d%d",&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++)
a[i][j]=a[i][j-1]+a[i-1][j]-a[i-1][j-1]+b[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",a[i][j]);
printf("\n");
}
return 0;
}
```

Tags: C++ Algorithm

Posted on Wed, 03 Nov 2021 17:47:55 -0400 by jacomus