2024.1.21 寒假训练记录(4)

花了大半天学了树套树(树状数组套主席树部分),题目还没有完全做完,明天继续做完剩下的一题和再往后学一下线段树套平衡树,代码能力好弱啊啊,今天把离散化写假了导致调了好久好久。目前还在坚持每天一场vp或者集训队的训练赛,希望思维上能尽快回到期末月前的状态。

昨天集美大学的校赛出到G,今天从H开始补。

(J线段树啊啊啊今天不补了,最近写数据结构写得头昏脑涨想创飞全人类qaq

文章目录

  • CF 1808A Lucky Numbers
  • CF 1808B Playing in a Casino
  • CF 1808C Unlucky Numbers
  • CF 1808D Petya, Petya, Petr, and Palindromes
  • 牛客 集美大学校赛H 卯酉东海道
  • 牛客 集美大学校赛I 简单的背包问题

CF 1808A Lucky Numbers

题目链接

最大情况就是出现0和9,每100个数一定会出现一次90,所以如果l和r的差值大于100的话,就把范围缩小到100个数之内就好了

#include 

using namespace std;

#define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

void solve()
{
	int l, r;
	cin >> l >> r;
	if (l > r) swap(l, r);
	if (r - l >= 100)
	{
		for (int i = l; i <= r; i ++ )
		{
			if (i % 100 == 90)
			{
				cout << i << '\n';
				return;
			}
		}
	}
	else
	{
		int ans = 0;
		string anss = to_string(l);
		for (int i = l; i <= r; i ++ )
		{
			string ss = to_string(i);
			char maxx = ss[0], minn = ss[0];
			for (int j = 0; j < ss.size(); j ++ )
			{
				maxx = max(maxx, ss[j]);
				minn = min(minn, ss[j]);
			}
			if (maxx - minn > ans)
			{
				ans = maxx - minn;
				anss = ss;
			}
		}
		cout << anss << '\n';
	}
}

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

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

CF 1808B Playing in a Casino

题目链接

利用前缀和,把每一列排好序,分别计算每一个数和其余数的差值就行

#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, m;
    cin >> n >> m;
    vector<vector<int>> g(m + 1, vector<int>(n + 1));
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            cin >> g[j][i];

    int ans = 0;
    for (int i = 1; i <= m; i ++ )
    {
        sort(g[i].begin(), g[i].end());
        vector<int> pre(n + 1);
        for (int j = 1; j <= n; j ++ ) pre[j] = pre[j - 1] + g[i][j];
        for (int j = 1; j <= n; j ++ )
        {
            ans += g[i][j] * (n - 1) - pre[j - 1] + (pre[n] - pre[j] - g[i][j] * (n - 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 1808C Unlucky Numbers

题目链接

vp的时候没想出来,如果两个数位数不相同的话,直接取和l的位数一样,每一位全是9的数即可;如果位数相同,l和r分别判断:每次取前缀加上后面每一位0-9(讲的好乱)看代码好了

本质上能这么构造的原因是,先确定了前缀,后面未确定的数字取一样的和取不同的都是一样的,因为(这里只看最小值)比如说取1222和1111,反正前面的1222都有1了,2在最小值方面起不到任何作用,所以和取1111的效果是一样的

#include 

using namespace std;

#define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

void get(vector<int> &v, int x)
{
    while (x)
    {
        v.push_back(x % 10);
        x /= 10;
    }
    reverse(v.begin(), v.end());
}

void solve()
{
	int l, r;
    cin >> l >> r;
    vector<int> lv, rv;
    get(lv, l), get(rv, r);
    if (lv.size() != rv.size())
    {
        int ans = 0;
        while (ans < l) ans = ans * 10 + 9;
        cout << ans << '\n';
        return;
    }
    else
    {
        int ans = 10;
        int haha;
        function<void(int, vector<int>)> check = [&](int x, vector<int> v)
        {
            int maxx = 0, minn = 10;
            for (auto i : v)
            {
                maxx = max(maxx, i);
                minn = min(minn, i);
            }
            if (maxx - minn < ans)
            {
                ans = maxx - minn;
                haha = x;
            }
        };
        check(l, lv), check(r, rv);
        function<void(vector<int>)> work = [&](vector<int> v)
        {
            int tmp = 0;
            for (int i = 0; i < v.size(); i ++ )
            {
                for (int j = 0; j <= 9; j ++ )
                {
                    int res = tmp;
                    for (int k = i; k < v.size(); k ++ ) res = res * 10 + j;
                    if (res < l || res > r) continue;
                    vector<int> temp;
                    get(temp, res);
                    check(res, temp);
                }
                tmp = tmp * 10 + v[i];
            }
        };
        work(lv), work(rv);
        cout << haha << '\n';
    }
}

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

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

CF 1808D Petya, Petya, Petr, and Palindromes

题目链接

从这道题得到的一个教训就是往函数里传vector,以后还是都加上引用吧,说不准啥时候就会t得很惨

这道题告诉我们的一个贡献问题的思路,当贡献不好累加时就考虑从最大的贡献开始减去不符合情况的部分

#include 

using namespace std;

#define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

const int N = 2e5 + 10;
vector<int> info[N][2];

void solve()
{
	int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ )
    {
        int x; cin >> x;
        info[x][i & 1].push_back(i);
    }
    if (k == 1)
    {
        cout << 0 << '\n';
        return;
    }
    int ans = (k / 2) * (n - k + 1);
    auto find = [&](vector<int>& v, int l, int r)
    {
        return upper_bound(v.begin(), v.end(), r) - lower_bound(v.begin(), v.end(), l);
    };
    for (int i = 1; i <= 2e5; i ++ )
    {
        for (int j = 0; j < 2; j ++ )
        {
            for (auto tmp : info[i][j])
            {
                int l = max((i64)1, max((2 + 2 * (k / 2) - tmp), (tmp + 1 - k)));
                int r = min(tmp - 1, 2 * n - 2 * (k / 2) - tmp);
                if (l <= r) ans -= find(info[i][j], l, r);
            }
        }
    }
    cout << ans;
}

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

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

牛客 集美大学校赛H 卯酉东海道

题目链接

现在一看当时没做真的很不应该,真的挺简单的一道题啊啊啊,Dijkstra中的dist多加一维存一下颜色就可以了

#include 

using namespace std;

// #define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

const int N = 100010;

struct Edge
{
	int v, col, w;
};

struct Node
{
	int v, d, c;
	bool operator> (const Node &tmp) const
	{
		if (d != tmp.d) return d > tmp.d;
		else return c > tmp.c;
	}
};

void solve()
{
	int n, m, l, base;
	cin >> n >> m >> l >> base;
	vector<vector<Edge>> g(n + 1);
	for (int i = 0; i < m; i ++ )
	{
		int u, v, col, w;
		cin >> u >> v >> col >> w;
		g[u].push_back({v, col, w});
	}

	vector<vector<int>> dist(n + 1, vector<int>(l + 1, 0x3f3f3f3f));
	priority_queue<Node, vector<Node>, greater<Node>> q;
	for (int i = 1; i <= l; i ++ )
	{
		dist[1][i] = 0;
		q.push({1, 0, i});
	}
	while (q.size())
	{
		auto t = q.top();
		q.pop();

		int ver = t.v, color = t.c, dd = t.d;

		for (int i = 0; i < g[ver].size(); i ++ )
		{
			int j = g[ver][i].v, cc = g[ver][i].col, w = g[ver][i].w;
			if (cc == color)
			{
				if (dist[j][cc] > dist[ver][cc] + w)
				{
					dist[j][cc] = dist[ver][cc] + w;
					q.push({j, dist[j][cc], cc});
				}
			}
			else
			{
				if (dist[j][cc] > dist[ver][color] + w * base)
				{
					dist[j][cc] = dist[ver][color] + w * base;
					q.push({j, dist[j][cc], cc});
				}
			}
		}
	}
	int ans = 0x3f3f3f3f;
	for (int i = 1; i <= l; i ++ ) ans = min(ans, dist[n][i]);
	if (ans != 0x3f3f3f3f) cout << ans << '\n';
	else cout << -1 << '\n';
}

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

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

牛客 集美大学校赛I 简单的背包问题

题目链接

还是很板的一题:dp+二分

#include 

using namespace std;

#define int long long

using i64 = long long;
using i128 = __int128_t;

typedef pair<int, int> PII;

const int N = 10010;

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

	vector<int> dp(N, 1e18);
	dp[0] = 0;
	for (int i = 1; i <= n; i ++ )
	{
		int w, v;
		cin >> w >> v;
		for (int j = N - 1; j >= v; j -- )
		{
			dp[j] = min(dp[j], dp[j - v] + w);
		}
	}

	for (int i = N - 2; i >= 0; i -- )
	{
		dp[i] = min(dp[i], dp[i + 1]);
	}

	int q; cin >> q;
	while (q -- )
	{
		int maxx; cin >> maxx;
		int ans = upper_bound(dp.begin(), dp.end(), maxx) - dp.begin() - 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();
    }
}

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