2024.1.18 寒假训练记录(1)

期末考试期间没怎么刷题,空下来就看看某乎,看了不少退役ACMer的记录和建议,觉得自己对于题目的思考还是太浅了,很多题目搞懂就过去了(甚至没有搞懂也就过去了),也没有去思考到底这些想法是怎么来的,这期间看到的一句话对我感触很深,就是要从大量题目的偶然中寻找一定的必然,所以在寒假期间记录一下想法以及督促自己训练。

文章目录

  • CF 1920A Satisfying Constraints
  • CF 1920B Summation Game
  • CF 1920C Partitioning the Array
  • CF 1920D Array Repetition
  • CF 1920E Counting Binary Strings
  • CF 1920F1 Smooth Sailing (Easy Version)

CF 1920A Satisfying Constraints

题目链接

遍历每个条件,维护满足已遍历条件的左右端点即可,条件3记录在set里最后再判断处理

#include 

using namespace std;

#define int long long

using i64 = long long;

typedef pair<int, int> PII;

void solve()
{
    int n;
    cin >> n;
    int l = -1e9, r = 1e9;
    set<int> st;
    for (int i = 0; i < n; i ++ )
    {
        int a, x;
        cin >> a >> x;
        if (a == 1) l = max(x, l);
        else if (a == 2) r = min(r, x);
        else if (a == 3) st.insert(x);
    }

    if (l > r) cout << 0 << '\n';
    else
    {
        int ans = r - l + 1;
        for (auto t : st)
        {
            if (t >= l && t <= r) ans -- ;
        }
        cout << ans << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

CF 1920B Summation Game

题目链接

这题犯的错误就是读题不够仔细,首先没有注意到数组中只有正数,还去特判了负数,其次就是初始化最小值的时候一定要注意数据范围,一开始初始化成-1e8直接wa了三发,实际要到-1e9才可以qaq

思路就是暴力枚举第一个人需要从大到小删掉多少个数,利用一下前缀和,维护最优情况就可以

#include 

using namespace std;

#define int long long

using i64 = long long;

typedef pair<int, int> PII;

void solve()
{
    int n, a, b;
    cin >> n >> a >> b;
    vector<int> num(n + 1);
    int sum = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> num[i];
        sum += num[i];
    }
    if (n == 1)
    {
        cout << 0 << '\n';
        return;
    }
    sort(num.begin(), num.end());
    vector<int> pre(n + 1);
    for (int i = 1; i <= n; i ++ ) pre[i] = pre[i - 1] + num[i];
    
    int temp = -1e18;
    for (int i = 0; i <= a; i ++ )
    {
        int tmp1 = pre[n] - pre[n - i];
        int tmp2 = pre[n - i] - pre[max((i64)0, n - i - b)];
        temp = max(temp, sum - tmp1 - tmp2 * 2);
    }
    cout << temp << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

CF 1920C Partitioning the Array

题目链接

这题中学到的结论是:两个数模上同一个数m的余数相同,那么这两个数的差值一定是m的倍数

#include 

using namespace std;

// #define int long long

using i64 = long long;

typedef pair<int, int> PII;

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

    int ans = 0;
    for (int i = 1; i <= n; i ++ )
    {
        if (n % i != 0) continue;
        int tmp = 0;
        for (int j = 0; j + i < n; j ++ )
        {
            tmp = __gcd(tmp, abs(a[j] - a[j + i]));
        }
        ans += (tmp != 1);
    }
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

CF 1920D Array Repetition

题目链接

遇到包含重复区间且数据很大,无法线性处理的情况,可以考虑通过取模将重复的大数据映射到小范围内

#include 

using namespace std;

// #define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

void solve()
{
    int n, q;
	cin >> n >> q;

	map<i64, i64> mp;
	vector<pair<i128, i128>> cp;
	i128 len = 0;

	for (int i = 0; i < n; i ++ )
	{
		int op, x;
		cin >> op >> x;

		if (op == 1) mp[ ++ len] = x;
		else
		{
			if (len > 1e18) continue;
			i128 tmp = len;
			len = len * (x + 1);
			if (len > 1e18) len = 1e18 + 1;
			cp.push_back(make_pair(len, tmp));
		}
	}

	while (q -- )
	{
		i64 k; cin >> k; 
		while (!mp.count(k))
		{
			int pos = lower_bound(cp.begin(), cp.end(), make_pair((i128)k, (i128)0)) - cp.begin();
			k = k % cp[pos].second;
			if (k == 0) k = cp[pos].second;
		}
		cout << mp[k] << ' ';
	}
	cout << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

CF 1920E Counting Binary Strings

题目链接

首先考虑最简单的情况(突然发现dp好像就是这样,简单的想明白了可能状态转移方程也就能推出来了((?

#include 

using namespace std;

#define int long long

const int mod = 998244353;

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

void solve()
{
    int n, k;
    cin >> n >> k;
    vector<vector<int>> dp(n + 1, vector<int>(k + 1));
    for (int i = 0; i <= k; i ++ ) dp[0][i] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= k; j ++ )
        {
            dp[i][j] = 0;
            for (int p = 0; i - j * p >= 0 && j + p - 1 <= k; p ++ )
            {
                dp[i][j] = (dp[i][j] + dp[i - j * p][p]) % mod;
            }
        }
    }
    int ans = 0;
    for (int i = 0; i <= k; i ++ ) ans = (ans + dp[n][i]) % mod;
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

CF 1920F1 Smooth Sailing (Easy Version)

题目链接

第一次做2500的题,发现没有我想象中的困难,算法本质上还是简单的,主要是思路要清晰以及代码能力要强

多源最短路(可能不是严格的多源最短路)(就是起点有很多,但是最短路径的长度只存储离该点最近的起点的长度)用BFS即可,先將所有起点都存进queue,然后和普通情况一样做(这和超级源点的思路也是一样的,即设置一个超级源点,向所有起点连一条权值是0的边(不过这种二维地图的图论,超级源点好像不太好做,所以像这样直接把所有起点传进去就可以了))

#include 

using namespace std;

// #define int long long

const int mod = 998244353;

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1};
int dy[8] = {1, -1, 0, 0, -1, 1, 1, -1};

void solve()
{
    int n, m, qq;
    cin >> n >> m >> qq;
    vector<string> g(n);
    for (int i = 0; i < n; i ++ ) cin >> g[i];

    queue<PII> q;
    vector<vector<int>> dist(n, vector<int>(m, 1e9));
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ ) 
            if (g[i][j] == 'v')
            {
                q.push(make_pair(i, j));
                dist[i][j] = 0;
            }

    while (q.size())
    {
        auto t = q.front();
        q.pop();

        int x = t.first, y = t.second;
        for (int i = 0; i < 4; i ++ )
        {
            int nx = x + dx[i], ny = y + dy[i];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if (dist[nx][ny] > dist[x][y] + 1)
            {
                dist[nx][ny] = dist[x][y] + 1;
                q.push(make_pair(nx, ny));
            }
        }
    }

    while (qq -- )
    {
        int x, y;
        cin >> x >> y;
        x -- , y -- ;

        function<bool(int)> check = [&](int mid)
        {
            vector<vector<int>> st(n, vector<int>(m));

            queue<PII> q;
            q.push(make_pair(x, y));
            st[x][y] = 1;
            while (q.size())
            {
                auto t = q.front();
                q.pop();

                int xx = t.first, yy = t.second;
                for (int i = 0; i < 4; i ++ )
                {
                    int nx = xx + dx[i], ny = yy + dy[i];
                    if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                    if (g[nx][ny] == '#') continue;
                    if (st[nx][ny]) continue;
                    if (dist[nx][ny] < mid) continue;
                    st[nx][ny] = 1;
                    q.push(make_pair(nx, ny));
                }
            }

            for (int i = 0; i < n; i ++ )
                for (int j = 0; j < m; j ++ )
                    if (g[i][j] == '#')
                    {
                        st[i][j] = 2;
                        q.push(make_pair(i, j));
                    }

            while (q.size())
            {
                auto t = q.front();
                q.pop();

                int xx = t.first, yy = t.second;
                if (xx <= 0 || xx >= n - 1 || yy <= 0 || yy >= m - 1) return false;

                for (int i = 0; i < 8; i ++ )
                {
                    int nx = xx + dx[i], ny = yy + dy[i];
                    if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                    if (st[nx][ny]) continue;
                    st[nx][ny] = 2;
                    q.push(make_pair(nx, ny));
                }
            }
            return true;
        };

        int l = 0, r = dist[x][y];
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        cout << r << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t = 1;
    // cin >> t;
    while (t -- )
    {
        solve();
    }
}

你可能感兴趣的:(2024寒假训练记录,算法)