2022 Niuke winter vacation algorithm basic training camp 3

Posted by zysac on Sun, 30 Jan 2022 16:06:42 +0100

E -- easy version of zhinai

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

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

int a[N];
bool st[N];

bool cmp(char a,char b)
{
    return a > b;
}

int main()
{
    int n, m, k;
    cin >> n >> m >> k;
    string str;
    cin >> str;
    for(int i = 0; i < n; i ++ ) cin >> a[i];

    for(int i = 0; i < n; i ++)
    {
        if(st[i]) continue;
        st[i] = true;

        int r = i + 1;
        while(a[r] == a[i]) st[r] = true, r ++;
        int l = i - 1;
        while(a[l] == a[i]) st[l] = true, l --;
        sort(str.begin() + l + 1, str.begin() + r, cmp);
    }

    long long ll = 0, cnt = 1;
    for(int i = str.size() - 1; i >= 0; i --)
        ll = (ll % mod + (str[i] - '0') * cnt % mod) % mod, cnt = cnt * 10 % mod;
    cout << ll % mod << endl;


    while(k -- )
    {
        int c, b;
        cin >> c >> b;
        for(int i = 0; i < str.size(); i ++ )
            if(a[i] == c) a[i] = b;

        memset(st, false, sizeof st);
        for(int i = 0; i < n; i ++)
        {
            if(st[i]) continue;
            st[i] = true;

            int r = i + 1;
            while(a[r] == a[i]) st[r] = true, r ++;
            int l = i - 1;
            while(a[l] == a[i]) st[l] = true, l --;
            sort(str.begin() + l + 1, str.begin() + r, cmp);
        }

        ll = 0, cnt = 1;
        for(int i = str.size() - 1; i >= 0; i --)
            ll = (ll % mod + (str[i] - '0') * cnt % mod) % mod, cnt = cnt * 10 % mod;
        cout << ll % mod << endl;
    }

    return 0;
}

There are a lot of redundant places, and the submission is all wrong at the beginning, and all the samples have passed...

The reason is that when you convert a string to a number, c n t ∗ = 10 cnt *= 10 CNT ∗ = 10, which should be written as CNT = cnt * 10% Mod
Take a chestnut for example: when cnt = 1e13, the mold is not taken, and ll = 1e8
cnt * str[i] - '0' overflows directly!!!!

The array partition i wrote is based on i and searches on both sides
There is a simple way to find the conversion from character to number + modulus

	for (int i = 0; i < str.size(); ++i)
    {
        ret = ret * 10 + (s[i] - '0');
        ret %= mod;//One step in place, much easier!
    }

The array partition i wrote is based on i and searches on both sides
Simple array partitioning

//The array starts with 1
for (int l = 1, r = 1; l <= n; l = r + 1, r = l)
{//l equals r+1 first, then r = 1 = R (original) + 1
    while (r < n && (a[l]==a[r+1]) ) ++r;
    printf("[%d,%d] ",l ,r);
}

When sort needs to be transferred to the sort function, if the cmp function does not need to be reused, you can use the anonymous function to define it directly when calling the sort function. (speed up the code), 🐂 ah 🐂 Ah)

sort(a + 1, a + 1 + n, [](const int&A, const int&B) {
     return A > B;
});

B - zhinaimai melon


The problem is the simple deformation of 01 backpack. The key is that the size of the array is not appropriate during the game!!! It's hard

The problem is that it's not clear d p [ i ] [ j ] dp[i][j] The specific meaning of dp[i][j] array I means considering the first I watermelons, and j means the current weight, so the value of J should be 2e3+10 instead of querying the upper limit of weight. M(1e3 + 10) is an instinctive problem, which is still too delicious

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

using namespace std;

const int N = 2e3 + 10, mod = 1e9 + 7;

long long w[N];
int dp[N][N];

int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ ) cin >> w[i];

    dp[0][0] = 1;
    for(int i = 1; i <= n; i ++ ){
//         dp[i][w[i]] = dp[i][w[i]] + 1, dp[i][w[i] / 2] = dp[i][w[i] / 2] + 1;
        for(int j = 0; j <= m; j ++ ){
            dp[i][j] = dp[i - 1][j];
            if(j >= w[i]) dp[i][j] = (dp[i][j] + dp[i - 1][j - w[i]] ) % mod;
            if(j >= w[i] / 2) dp[i][j] = (dp[i][j]  + dp[i - 1][j - w[i] / 2]) % mod;
        }
    }

    for(int i = 1; i <= m; i ++ )
        cout << dp[n][i] % mod << " ";

    return 0;
}

Note that the starting condition is generally written as dp[0][0] = 0, because considering the first 0 watermelons, the number of schemes when the weight is 0 itself is 1

L - zhinai's database

Just simulate. I have a knowledge point
There is a find function in the string. When the corresponding character is not found in the string, it will return npos
Take a chestnut

if(str.find(ch) != str.npos) cout << "find" << endl;

I -- zhinai's password


If an interval of a topic has monotonic property, it can be divided into two parts. However, if the topic does not have monotonic property, but has some interval property, we can also use two parts—— yxc boss
This question has interval property.

Idea: ① suppose x is the minimum number satisfied. If Y > = x, then y also meets the answer. Isn't this transformed into finding the minimum in the maximum, then it's time to start dichotomy.
Bisection boss template

② Because it is an interval, we need to consider various situations in the interval. We need to use prefix and (reduce the time complexity of query) to record capital letters, lowercase letters, numbers and other characters respectively. There is no need to traverse in the interval of l~r.

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

using namespace std;

const int N = 1e5 + 10;

char str[N];
long long a[N], b[N], c[N], d[N];

bool check(int l, int r)
{
    int ai = a[r] - a[l - 1], bi = b[r] - b[l - 1], ci = c[r] - c[l - 1], di = d[r] - d[l - 1];
    if((ai >= 1 && bi >= 1 && ci >= 1) ||  (ai >= 1 && ci >= 1 && di >= 1) || (ai >= 1 && bi >= 1 && di >= 1) || (bi >= 1 && ci >= 1 && di >= 1))
        return true;
    else return false;
}

int main()
{
    int n, L, R;
    cin >> n >> L >> R;
    cin >> str + 1;

    for(int i = 1; i <= n; i ++ )
    {
        if(str[i] >= 'A' && str[i] <= 'Z') a[i] ++;
        else if(str[i] >= 'a' && str[i] <= 'z') b[i] ++;
        else if(str[i] >= '0' && str[i] <= '9') c[i] ++;
        else d[i] ++;
        a[i] += a[i - 1];
        b[i] += b[i - 1];
        c[i] += c[i - 1];
        d[i] += d[i - 1];
    }

    long long ans = 0;
    for(int i = 1; i <= n - L + 1; i ++ )//i must end at n-L+1, because if i > n-L+1, l and r still exist, which may be tenable
    {
        int l = min(n, i + L - 1), r = min(n, i + R - 1);
        int y = r;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(check(i, mid)) r = mid;
            else l = mid + 1;
        }
        if(!check(i, r)) continue;
        ans += y - r + 1;
    }
    cout << ans << endl;

    return 0;
}

i of two points must end at n-L+1, because if i > n-L+1, l and r still exist, which may be tenable and increase the total

Topics: C++ Algorithm