Remember the written test questions of a certain residence

The online written test of a certain residence is cool, so I sent it to see if anyone can give me some advice on how to solve the problem;

1. Topic 1

1.1 Question

There are two arrays with length n (1 - 5000), namely a and b (1 - 10000000). The degree of liking is defined as the sum of ai*bi. You can choose
an interval of b and flip it once to ask for the maximum degree of liking
. Example:
3
10 1 1
1 10 1
Output:
102
Explanation:
The interval of flipped b array is [1, 2], after flipping it is 10 1 1, a array is 10 1 1, the corresponding bits are multiplied and summed to 102;

1.2 Violent solution ideas

Idea:
Enumerate the intervals, for each interval, flip the elements in the interval in the array, calculate the like degree after flipping and update the maximum value, and finally output the maximum like degree. The time complexity is O(n^3)
code:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    
    
    int n;
    cin >> n;

    vector<int> a(n);
    vector<int> b(n);
    for (int i = 0; i < n; i++) {
    
    
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
    
    
        cin >> b[i];
    }

    // 计算原始的喜欢程度
    long long ans = 0;
    for (int i = 0; i < n; i++) {
    
    
        ans += (long long)a[i] * b[i];
    }

    // 枚举区间,计算翻转区间后的喜欢程度
    for (int i = 0; i < n; i++) {
    
    
        for (int j = i; j < n; j++) {
    
    
            // 翻转区间
            reverse(a.begin() + i, a.begin() + j + 1);

            // 计算喜欢程度
            long long cur = 0;
            for (int k = 0; k < n; k++) {
    
    
                cur += (long long)a[k] * b[k];
            }

            // 更新最大值
            ans = max(ans, cur);

            // 恢复原数组
            reverse(a.begin() + i, a.begin() + j + 1);
        }
    }

    cout << ans << endl;

    return 0;
}

1.3 Optimization ideas for AI generation

Idea:
I can provide you with a solution based on greedy algorithm and prefix sum optimization, with a time complexity of O(n).

First, we can convert the product ai bi to (a+b) (ab), where a = (ai+bi)/2 and b = (ai-bi)/2. We only need to consider the largest (a+b) and (ab).

Taking (a+b) as an example, we can first calculate the difference between all two adjacent elements diff[i] = (a[i+1]+b[i+1]) - (a[i]+b [i]), then you can judge whether the position of the interval needs to be flipped based on the sign of the difference. Specifically, we define sum1 = a[1]+b[1], sum2 = a[1]-b[1], and then loop from position i=2:

  • If diff[i] > 0, it means that a[i]+b[i] is larger than a[i-1]+b[i-1], which means that there are better choices for the subsequent candidate intervals. We record maxSum = max(maxSum, sum1+sum2) and mark the interval [start, i] that needs to be flipped, and update sum1 and sum2 at the same time.
  • If diff[i] <= 0, it means that the current position i-1 may need to be added to the candidate interval, and we only need to update sum1 and sum2.

For the update of maxSum, if the current interval that needs to be flipped is [start, end], then we can flip a[start], b[start] and a[end], b[end], that is, exchange a[start ] and a[end], exchange b[start] and b[end] to get the new (maxSum, maxA, maxB). Note that we only need to select the segment with the largest a+b in the interval that needs to be flipped, but we do not need to select the largest interval that needs to be flipped. Because it is possible that the difference between some intervals is very small and will be flipped many times, resulting in high time complexity.

Finally, we need to calculate the existence of the flipped interval [start, end] again, and perform prefix sum optimization on a and b respectively to quickly calculate the interval sum. Specifically, we calculate the prefixes and sa and sb of a and b respectively, and then the maximum liking degree n is equal to a and sa in the interval [1, start-1], plus a and sa in the interval [start, end] The absolute value of the difference, plus a and sa in the interval [end+1, n], is multiplied by b and sb. Similar calculations can get the answer.

The code is implemented as follows:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
int n, a[MAXN], b[MAXN];
long long sa[MAXN], sb[MAXN];
int diff[MAXN], pos[MAXN];
long long maxSum, maxA, maxB;
void solve()
{
    
    
    sa[0] = sb[0] = pos[0] = 0;
    for (int i = 1; i <= n; ++i) {
    
    
        cin >> a[i] >> b[i];
        sa[i] = sa[i - 1] + a[i];
        sb[i] = sb[i - 1] + b[i];
        pos[i] = i - 1;
        diff[i] = a[i] + b[i] - a[i-1] - b[i-1];
    }
    maxSum = sa[1] + sb[1] + sa[n] - sa[1] + sb[n] - sb[1];
    maxA = sa[1] - sb[1];
    maxB = sb[1] - sa[1];
    int start = 1, end = 0;
    long long sum1 = sa[1] + sb[1], sum2 = sa[1] - sb[1];
    for (int i = 2; i <= n; ++i) {
    
    
        if (diff[i] > 0) {
    
    
            long long tmpSum1 = sum1 + sa[i] - sa[start] + sb[n] - sb[i-1];
            long long tmpSum2 = sum2 + sa[i] - sa[start] - sb[n] + sb[i-1];
            if (tmpSum1 + tmpSum2 > maxSum) {
    
    
                maxSum = tmpSum1 + tmpSum2;
                maxA = tmpSum1 / 2;
                maxB = tmpSum2 / 2;
                if (i <= n - 1 && diff[i+1] <= 0 && sa[i+1]-sa[start] > sb[n]-sb[i]) {
    
    
                    ++i;
                    tmpSum1 += sa[i] - sa[start] - sb[n] + sb[i-1];
                    tmpSum2 += sb[n] - sb[i-1] - sa[i] + sa[start];
                }
                start = pos[i] + 2;
                end = i;
            }
            sum1 += sa[i] - sa[start] + sb[i] - sb[start-1];
            sum2 += sa[i] - sa[start] - sb[i] + sb[start-1];
        } else {
    
    
            sum1 += sa[i] - sa[i-1];
            sum2 += sb[i] - sb[i-1];
            pos[i] = pos[i-1];
        }
    }
    sum1 = sa[n] - sa[start-1];
    sum2 = sb[n] - sb[start-1];
    for (int i = n; i >= end+1; --i) {
    
    
        diff[i] = a[i] + b[i] - a[i-1] - b[i-1];
        if (diff[i] <= 0) {
    
    
            sum1 -= sa[i] - sa[end+1];
            sum2 -= sb[i] - sb[end+1];
        }
    }
    long long answer = abs(sum1*maxB) + abs(sum2*maxA);
    cout << answer << endl;
}
int main()
{
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    solve();
    return 0;
}

In the code, we use sa and sb to store the prefix sum of a and b, diff stores the difference between two adjacent elements, and pos stores the left endpoint of the interval that needs to be flipped. For the update of maxSum, we also need to consider whether the currently selected interval can be merged with subsequent adjacent intervals to get a better choice.

Finally, we can perform prefix sum optimization on a and b respectively to quickly calculate the interval sum. When calculating likeability, we also need to pay attention to the absolute value.

In summary, the time complexity of this greedy algorithm is O(n), which is more efficient than brute force methods and dynamic programming methods, and can solve problems with large data sizes.

mmd, the code for the optimization idea doesn’t seem right, it’s numb.

2. Simulate encryption and decryption questions

Question:
For a string: kingsoft, grandpa likes to encrypt it. The encryption method is to take the head first, then the tail, until it is finished. After
encrypting according to grandpa’s encryption method, it looks like this: ktifnogs, now grandpa has transmitted it to you, you Need to decrypt and output a string.
I didn’t think of any optimization for this question, so I just reversed the encryption method to get it. What I need to pay attention to is the problem of getting odd and even characters, and nothing else;

3. Dynamic programming questions

forget

Guess you like

Origin blog.csdn.net/BinBinCome/article/details/131025687