Dichotomy & prefix and

Binary sum prefix sum

1, Dichotomy

Write before:

If there is monotonicity, it can be dichotomized. If there is no monotonicity, it can also be dichotomized

Idea:

  1. mid=l+r+1>>1
    1. If the conditions are met, the answer is [mid,r]; l=mid
    2. If not, the answer is [l,mid-1]; r=mid-1
  2. mid=l+r>>1
    1. If the conditions are met, the answer is [l,mid]; r=mid;
    2. If the conditions are not met, the answer is [mid+1,r];l=mid+1;
//When we divide the interval [l, r] into [l, mid] and [mid + 1, r], the update operation is r = mid or l = mid + 1;, It is not necessary to add 1 when calculating mid.
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

//When we divide the interval [l, r] into [l, mid - 1] and [mid, r], the update operation is r = mid - 1 or l = mid;, At this time, in order to prevent dead circulation, add 1 when calculating mid.
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
1. Range of numbers

Given an array of integers of length n in ascending order and q queries.

For each query, the start and end positions of an element k are returned (the positions are counted from 0).

If the element does not exist in the array, - 1 - 1 is returned.

Input format
The first line contains integers n and q, indicating the length of the array and the number of queries.

The second line contains n integers (all in the range of 1 ∼ 10000), representing the complete array.

The next q lines, each containing an integer k, represent a query element.

Output format
There are q rows in total, and each row contains two integers, indicating the starting position and ending position of the element.

If the element does not exist in the array, - 1 - 1 is returned.

Data range
1≤n≤100000
1≤q≤10000
1≤k≤10000
Input example:
6 3
1 2 2 3 3 4
3
4
5
Output example:
3 4
5 5
-1 -1

Problem solving ideas:

This is a classic template question. That is, first find the left end point of the interval by binary search, and then find the right end point.

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

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

int main(){
    cin>>n>>q;
    for(int i=0;i<n;i++) cin>>num[i];
    while(q--)
    {
        int x;
        cin>>x;
       	int l=0,r=n-1;
        while(l<r)
        {
            int mid=l + r >>1;//It is equivalent to shifting the whole result represented by binary after l+r by one bit to the right, that is, the whole is divided by 2
           	if(x<=num[mid])//Here x can be equal to num[mid], indicating that x is on the left in the middle of the array
                r=mid;//Limit right endpoint
            else l=mid+1;
        }
        if(x==num[r]) cout<<r<<" ";
        r=n-1;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(num[mid]<=x) l=mid;//Here is l=mid, so mid should be written as L + R + 1 > > 1
            else r=mid-1;
        }
        if(x==num[l]) cout<<l<<endl;
        else 
        cout<<"-1 -1"<<endl;
    }
   
    return 0;
}
2. The cubic root of a number

Given a floating-point number n, find its cubic root.

Input format
A row containing a floating-point number n.

Output format
There is one line, including a floating point number, which represents the solution of the problem.

Note that the result retains 6 decimal places.

Data range
−10000≤n≤10000
Input example:
1000.00
Output example:
10.000000

Problem solving ideas:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

int main(){
    double n;
    cin>>n;
    double l=-10000,r=10000;
    while(r-l>1e-8)
    {
        double mid=(l+r)/2;//double type cannot use shift operation
        if(mid*mid*mid>=n) r=mid;
        else l=mid;
    }
    printf("%.6f",l);
    return 0;
}
2, Prefix and

Prefixes and are mainly divided into;

One dimensional prefix and:

s[i]+=s[i-1]

2D prefix and:

s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1]

3. Prefix and

Enter a sequence of integers of length n.

Next, enter m more queries, and enter a pair of l,r for each query.

For each query, the sum of the number l to the number r in the original sequence is output.

Input format
The first line contains two integers n and m.

The second row contains n integers, representing the integer sequence.

The next m lines, each containing two integers l and r, represent the range of a query.

Output format
There are m lines in total, and each line outputs a query result.

Data range
1≤l≤r≤n,
1≤n,m≤100000,
− 1000 ≤ the value of the element in the sequence ≤ 1000
Input example:
5 3
2 1 3 6 4
1 2
1 3
2 4
Output example:
3
6
10

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=100010;
int sum[N];
int a[N];
int n,m;



int main(){

    cin>>n>>m;
    
    //Pretreatment
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        sum[i]=sum[i-1]+x;
    }
    
    
    while(m--)
    {
        int l,r;
        cin>>l>>r;
        cout<<sum[r]-sum[l-1]<<endl;
    }
    return 0;
}
4. Sum of submatrix

Enter an integer matrix with n rows and m columns, and then enter q queries. Each query contains four integers x1, Y1, X2 and Y2, representing the upper left corner coordinates and lower right corner coordinates of a sub matrix.

For each query, the sum of all numbers in the output submatrix.

Input format
The first line contains three integers n, m, q.

Next, n rows, each containing m integers, represent the integer matrix.

The next q line contains four integers x1, Y1, X2 and Y2, representing a set of queries.

Output format
There are q rows in total, and each row outputs a query result.

Data range
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
− 1000 ≤ value of elements in the matrix ≤ 1000
Input example:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
Output example:
17
27
21

Solution idea: first find the prefix and array, and then divide and calculate the prefix and matrix according to the obtained sub matrix

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=1010;
int n,m;
int q;
int g[N][N];
int sum[N][N];

int main(){
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++) 
        for(int j=1;j<=m;j++)//In order to avoid cross-border problems, I usually count the array from 1
        {
            cin>>g[i][j];
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+g[i][j];//Processing prefixes and arrays
            
        }
    
    
    while(q--)
    {
        int x1,x2,y1,y2;
        cin>>x1>>y1>>x2>>y2;
        //Using prefix and array to calculate the sum of a sub matrix
        cout<<sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]<<endl;
    }
    return 0;
}
3, Advanced
5. Robot jumping problem

The robot is playing an old DOS based game.

There are N+1 buildings in the game - numbered from 0 to N, arranged from left to right.

The height of Building No. 0 is 0 units, and the height of Building No. i is H(i) units.

At first, the robot was at the building numbered 0.

With each step, it jumps to the next (right) building.

Assuming that the robot is in building k and its current energy value is E, it will jump to building k+1 in the next step.

If H(k+1) > e, the robot will lose the energy value of H(k+1) − e, otherwise it will get the energy value of E − H(k+1).

The goal of the game is to reach the nth building. In this process, the energy value cannot be negative units.

The question now is, at least how much energy does the robot start the game to ensure the successful completion of the game?

Input format
Enter the integer N on the first line.

The second line is an integer separated by N spaces. H(1),H(2),..., H(N) represents the height of the building.

Output format
Output an integer representing the result after rounding the initial energy value of the minimum unit required.

Data range
1≤N,H(i)≤105,

Input example 1:
5
3 4 3 2 4
Output example 1:
4
Input example 2:
3
4 4 4
Output example 2:
4
Input example 3:
3
1 6 4
Output example 3:
3

Problem solving ideas:

Two cases:

1. If h (K + 1) > e: the energy after jumping is E-(H(k+1) − E)=2E-H(k+1)

2. If h (K + 1) < e: the energy after jumping is E+(E-H(k+1))=2E-H(k+1)

It can be found that the final energy values obtained in the two cases are the same, which can be obtained:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
const int N=100010;
int n;
int arr[N];


bool check(int e)
{
    for(int i=0;i<n;i++){
        e=e*2-arr[i];
        if(e>1e5) return true;//If the current energy E is greater than 1e5 (maximum), the double e minus one number must still be greater than 1e5 (maximum)
        if(e<0) return false;//Non negative energy value
    }
    return true;
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    
    //Binary search energy value
    int l=0,r=1e5;
    while(l<r)
    {
        int mid=r+l>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;//Cout < < R < < endl is the same, because l=r at this time
}
6. Sum of squares

The sum of Squares Theorem, also known as Lagrange's theorem:

Each positive integer can be expressed as the sum of squares of up to four positive integers.

If 0 is included, it can be expressed as the sum of the squares of four numbers.

For example:

5=02+02+12+22
7=12+12+12+22
For a given positive integer, there may be many representations of the sum of squares.

You are required to sort 4 numbers:

0≤a≤b≤c≤d
All possible representations are arranged in ascending order according to a, B, C and D as the joint primary key, and finally the first representation is output.

Input format
Enter a positive integer N.

Output format
Output 4 non negative integers, sorted from small to large, separated by spaces.

Data range
0<N<5∗106
Input example:
5
Output example:
0 0 1 2

Problem solving ideas:

If the violence algorithm is used, four for loops are used. The title requires to output the first four numbers arranged in dictionary order. Therefore, you can first select from the following two c and d, then record that the square sum of the two numbers has appeared and assigned a value, and then select a and b

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=5000010;
int C[N],D[N];//Hash table, whether two array records c*c+d*d have appeared
int n;

int main(){
    cin>>n;
    //There may be many pairs of c and d to make s the same, leaving the first pair of schemes
    memset(C,-1,sizeof C);
    for(int c=0;c*c<=n;c++)
    {
        for(int d=c;d*d+c*c<=n;d++)
        {
            int s=c*c+d*d;
            if(C[s]==-1)//If the current s has not appeared
            C[s]=c,D[s]=d;
        }
    }
      
    //
    for(int a=0;a*a<=n;a++)
    {
        for(int b=a;b*b+a*a<=n;b++)
        {
            int s=n-a*a-b*b;
            if(C[s]!=-1)//Judge that s has appeared
            {
                printf("%d %d %d %d\n",a,b,C[s],D[s]);
                return 0;
                
            }
        }
    }
      
}
7. Divide chocolate

On children's day, K children visited Xiao Ming's house.

Xiao Ming took out his precious chocolate to entertain the children.

Xiao Ming has a total of N chocolates, of which the i is Hi × A rectangle composed of Wi squares.

In order to be fair, Xiao Ming needs to cut K chocolates out of the N chocolates and give them to the children.

The cut chocolate needs to meet:

The shape is a square and the side length is an integer
Same size
For example, a piece of 6 × 5 chocolate can cut 6 pieces 2 × 2 chocolates or 2 pieces of 3 × 3 chocolate.

Of course, the children all hope to get as much chocolate as possible. Can you help Xiao Ming calculate the maximum side length?

Input format
The first line contains two integers N and K.

The following N lines each contain two integers Hi and Wi.

Input to ensure that each child can get at least one dollar × 1 chocolate.

Output format
Output the maximum possible side length of the cut square chocolate.

Data range
1≤N,K≤105,
1≤Hi,Wi≤105
Input example:
2 10
6 5
5 6
Output example:
2

Problem solving ideas:

The quantity of each piece of chocolate is given in the title. You can't splice the chocolate, you can only separate each piece of chocolate

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=100010;
int n,k;
int h[N],w[N];//Storage chocolate length and width


bool check(int mid){
    int res=0;
    for(int i=0;i<n;i++)
    {
        res+=(h[i]/mid)*(w[i]/mid);
        if(res>=k) return true;
    }
    return false;
}

int main(){
	cin>>n>>k;
    for(int i=0;i<n;i++) cin>>h[i]>>w[i];
    
    //Half find the side length of chocolate
    int l=1,r=1e5;//Here l starts from 1, because the minimum side length of chocolate is 1 and the maximum side length is 1e5
    while(l<r)
    {
        int mid=l+r+1>>1;
        if(check(mid)) l=mid;//Here is l=mid, so the corresponding mid should be added by 1 and divided by 2
        else r=mid-1;
    }
    cout<<l<<endl;
    return 0;
    
}
8. Laser bombs

There are N targets on the map. The integer Xi and Yi represent the position of the target on the map. Each target has a value Wi.

Note: different targets may be in the same location.

Now there is a new type of laser bomb that can destroy a bomb containing R × All targets in the square of R positions.

The laser bomb is positioned by satellite, but it has one disadvantage: its explosion range, that is, the side of the square must be parallel to the x and y axes.

If the target is on the edge of the blasting square, the target will not be destroyed

Ask how much a bomb can blow up a target with a total value on the map.

Input format
In the first line, enter positive integers N and R, representing the number of targets on the map and the side length of the square respectively. The data are separated by spaces.

Next, enter a set of data in N rows. Each group of data includes three integers Xi, Yi and WI, representing the x coordinate, y coordinate and value of the target respectively. The data are separated by spaces.

Output format
Output a positive integer, representing the total value of a bomb that can blow up the target on the map at most.

Data range
0≤R≤109
0<N≤10000,
0≤Xi,Yi≤5000
0≤Wi≤1000
Input example:
2 1
0 0 1
1 1 1
Output example:
1

Problem solving ideas:

This problem is a two-dimensional prefix sum problem. Only the intersection (target object) that can be framed in the frame can be blown up by the bomb. The bomb can only blow up targets within RxR range at most. If the box coincides with the edge, it can only blow up targets within (R-1) x (R-1).

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=5010;//Because X and Y do not exceed 5000 at most, R does not need such a large range, but only a number 1 greater than 5000
int n,m;
int s[N][N];

int main(){
    int cnt,r;
    cin>>cnt>>r;
    r=min(5001,r);
    
    n=m=r;
    while(cnt--)
    {
        int x,y,w;
        cin>>x>>y>>w;
        x++,y++;//To prevent boundary problems, move x and y back one bit as a whole
        n=max(n,x),m=max(m,y);
        s[x][y]+=w;
    }
    
    //Preprocessing prefix and
    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];//To save memory space, prefix and array are combined with the original array
    
    int res=0;
    
    //Enumerate all rectangles with side length R, and enumeration (i, j) is the lower right corner
    for(int i=r;i<=n;i++)
        for(int j=r;j<=m;j++)
        {
            res=max(res,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]);
        }
        
    cout<<res<<endl;
    return 0;
}
10.K-fold interval

Given a sequence of length N, A1,A2,... AN, if the sum of a continuous subsequence Ai,Ai+1,... Aj is a multiple of K, we call this interval [i,j] a k-fold interval.

Can you find out how many K-times intervals there are in the sequence?

Input format
The first line contains two integers N and K.

Each of the following N lines contains an integer Ai.

Output format
Output an integer representing the number of K-times intervals.

Data range
1≤N,K≤100000,
1≤Ai≤100000
Input example:
5 2
1
2
3
4
5
Output example:
6

Problem solving ideas:

You can use the violent algorithm first:

for(int R=1;R<=n;R++)
{
    for(int L=1;L<=R;L++)
    {
        int s=sum[R]-sum[L-1];
        if(s%k==0) res++;
    }
}

At this time, the time complexity of the algorithm is O(n^2), that is, (105) 2. At this time, 60% of the data can be passed, but can it be optimized? It can be found here that, (sum[r]-sum[l-1])%k==0 is equivalent to sum[r]%k==sum[l-1]%k, that is, the combination of prefix and% equal to k0 and the combination of two identical prefixes and% k meet the conditions. Therefore, cnt array can be used to record the number of the same prefix and% k, and then res adds cnt array to get the answer.

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=100010;
typedef long long LL;
LL sum[N],cnt[N];

int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>sum[i];
        sum[i]+=sum[i-1];//Building prefixes and arrays
    }
    
    LL res=0;
    cnt[0]=1;//Special judgment, when sum[i]=0, it is also a multiple of k
    for(int i=1;i<=n;i++)
    {
        res+=cnt[sum[i]%k];
        cnt[sum[i]%k]++;
    }
    cout<<res<<endl;
    return 0;
}

Tags: Algorithm

Posted on Thu, 25 Nov 2021 13:49:54 -0500 by eazyGen