Zou Yi, No. 8 middle school, Hengyang City, Hunan Province
Many problems have a constant state from which to evolve and transfer, resulting in sub problems with the same properties and smaller scale. So we start with this, analyze the constant state and weight, and then see how to transfer to produce the solution of another sub problem
For example, the following question:
Median problem
A nonnegative integer sequence a with length N is given_ i. For all 1 < = k < = (N + 1) / 2, output the median of the first 1, 3, 5.
Input
The first line is a positive integer n, which represents the sequence length. N<=10^5
Line 2 contains N integers a_ i (-10^9 < = A_i < = 10^9)
Output
As shown in the question.
Input data 1
7
5 7 8 2 3 1 9
Output data 1
5
7
5
5
Solution:
The essence of this question is to find the median of some numbers. If you only find the median once, it's very simple. Just do it quickly. The time complexity is O(N*Log2N). Of course, if you understand fast scheduling deeply enough, you can write O(N)
But this problem is to find the median for many times, and it is the median of the first 1, 3, 5, 7, 9... Numbers. This is obviously an arithmetic sequence with a tolerance of 2. After analysis, we can get
1: For an ascending sequence, if 2 numbers are inserted or reduced each time, the position of the median will only be offset by one position or remain unchanged. Taking reduction as an example, if two numbers are reduced, one on the left and one on the right of the median position, the median position remains unchanged; If both are on the left of the median position, the median will move one bit to the right, otherwise, it will move one bit to the left.
2: Because this question gives all the numbers in advance, it belongs to offline inquiry. Therefore, for the original sequence, after a quick row, we can know its position and then its weight according to the definition of median.
3: According to the constant quantity derived from the previous article, we analyze the next problem to be solved: find the median of the first five numbers. Obviously, we only need to remove the last two numbers from the sorted sequence. The consequences are analyzed in Article 1. Of course, at this time, we should be able to quickly find the position of the removed two numbers in the ascending sequence, and carry out corresponding processing according to the relationship between their position and the median position.
4: To get the corresponding results, we must remove the previous two numbers from the ascending sequence. It is not difficult to find that this problem needs to constantly delete elements, so we use the linked list structure for processing.
5: Continue to perform the above steps to obtain all solutions, and then output them
The code is as follows:
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int ans[N],pos[N],tot; struct node { int x,id; }a[N]; struct list { int l,r,v; }l[N]; void insert(int p,int v) { tot++,l[tot].v=v; l[tot].l=p,l[tot].r=l[p].r; l[l[p].r].l=tot,l[p].r=tot; } void erase(int p) { l[l[p].l].r=l[p].r; l[l[p].r].l=l[p].l; } bool cmp(node x,node y) { if(x.x==y.x) return x.id<y.id; return x.x<y.x; } int main() { int n,now,flag=0; scanf("%d",&n);now=n/2+1; for(int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].id=i; ans[1]=a[1].x; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { insert(tot,a[i].x); pos[a[i].id]=tot; } for(int i=n;i>=1;i--) { if(i%2==1) { if(flag>0) now=l[now].r; if(flag<0) now=l[now].l; flag=0; ans[i]=l[now].v; } if(pos[i]<now) flag++; if(pos[i]>now) flag--; erase(pos[i]); } for(int i=1;i<=n;i+=2) printf("%d\n",ans[i]); return 0; }
Example 2: Ksum
Give you an array of positive integers with a length of N, so this sequence has n(n+1)/2 sub segments. Now find the sum of the n(n+1)/2 sub segments and sort them in descending order. What is the number of the first K.
Input
The first line contains two integers n and K. The next line contains n positive integers representing the array. ai≤10^9 k≤n(n+1)/2, n≤100000,k≤100000
Output
Output K numbers, representing the first k numbers after descending order, separated by spaces
Input data 1
3 4
1 3 4
Output data 1
8 7 4 4
Through analysis, it is not difficult to find out
1: The maximum value of the whole sequence is obviously the sum of all numbers, that is, the number interval [1..N]
2: Now we want to get the sum of the interval with the second largest weight. Obviously, we should move the left end point 1 of interval [1..N] to the right by 1 bit, or the right end point N to the left by 1 bit, resulting from the two sub intervals [1..N-1] and [2..N]. But which of the two weights is greater? It's okay. Just throw it in the pile.
3: Then continue to derive the two derived sub intervals [1..N-1] and [2..N], and it will be found that the interval [2..N-1] will be derived twice. We can forcibly remove one and keep the other. So it is stipulated that for a certain interval
[L, R] the left boundary is allowed to move to the right only when R=N. Finally, the following derivatives can be obtained:
The code is as follows:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> using namespace std; struct node { int l,r; long long s; } t,z; int n,k,a[100010]; long long s; priority_queue<node> q; bool operator <(node a,node b) { return a.s<b.s; } int main() { scanf("%d%d",&n,&k); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); s+=a[i]; } t.s=s; t.l=1; t.r=n; q.push(t); for(int i=1; i<=k; i++) { t=q.top(); q.pop(); printf("%lld ",t.s); z.l=t.l; z.r=t.r-1; z.s=t.s-a[t.r]; q.push(z); if(t.r==n) { z.l=t.l+1; z.r=t.r; z.s=t.s-a[t.l]; q.push(z); } } return 0; }
Neighbor search
Given A sequence A of length n, the numbers in A are different. For each number Ai in A, find:
min|Ai − Aj|, where 1 ≤ J < I
And let the above formula take the minimum value of j (recorded as Pi). If the minimum value point is not unique, select the one that makes Aj smaller.
Input format
In the first line, enter the integer n, representing the length of the sequence.
On the second line, enter n integers A1... An, representing the specific values of the sequence, separated by spaces.
Output format
Output a total of n-1 lines, each line outputs two integers, separated by spaces.
Respectively represent the corresponding values of min|Ai − Aj| and Pi when i takes 2~n.
Data range
n≤10^5,|Ai|≤10^9
Input example:
3
1 5 3
Output example:
4 1 / / for 5, the smallest absolute value on its left and the difference is 1, and the difference is 4
2 1 / / for 3, the smallest absolute value on its left and the difference between it is 5, and the difference is 2
Solution:
The simplest way to solve this problem is to violently enumerate each number I, and then enumerate the numbers on the left, i.e. 1 to i-1
The simulation can be carried out according to the meaning of the problem, but the time complexity is obviously O(N^2). For this practice, it ensures the constraint of location relationship.
If we consider it from another angle, first consider the constraint of minimum difference.
Obviously, for a sequence, after sorting it, the number with the smallest difference must be its predecessor and successor.
Of course, the first number in the sequence has only a successor and no precursor. The last number in the sequence has only a precursor and no successor.
So we can arrange the sequence in ascending order.
For example: for the input sequence 3 2 9 5 4
After sorting, we get 2 3 4 5 9
Press down to ensure the position constraint, so we find the last number 4 in the input sequence because its position number is the largest.
It appears in the third position in the sequence 2 3 4 5 9. At this time, the 3 on the left and 5 on the right are smaller than it in the original sequence, which meets the requirements of the question.
So the difference is calculated. Next, we delete 4 from the sequence 2 3 4 5 9 to get 2 3 5 9. Then process the penultimate number 5 input in the original sequence
At this point, the problem becomes a smaller problem with the same nature. That is, the number 5 has the largest original position number in the sequence 2 3 5 9.
The code is as follows:
#include<bits/stdc++.h> using namespace std; const int N=1e5+2; int n,i,lx,rx,l[N],r[N],p[N]; struct str { int x,i; } a[N],ans[N]; bool cmp(str x,str y) { return x.x<y.x; } int main() { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].i=i; a[0].x=-3e9; a[n+1].x=3e9; sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++) l[i]=i-1,r[i]=i+1,p[a[i].i]=i; for(i=n;i;i--) { lx=abs(a[l[p[i]]].x-a[p[i]].x); rx=abs(a[r[p[i]]].x-a[p[i]].x); if(lx<=rx) ans[i]=(str){lx,a[l[p[i]]].i}; else ans[i]=(str){rx,a[r[p[i]]].i}; l[r[p[i]]]=l[p[i]]; r[l[p[i]]]=r[p[i]]; } for(i=2;i<=n;i++) printf("%d %d\n",ans[i].x,ans[i].i); return 0; }
There are other methods to solve the above problems, which will not be repeated here, but the thinking mode of this paper is reflected in many computer algorithms, such as dijkstra finding the shortest path, knapsack algorithm and so on.
In fact, the algorithm is constantly starting from a starting state to transfer the state. Just this transfer process, we can make it faster through many methods and means..