2022“杭电杯”中国大学生算法设计超级联赛(3)

2022“杭电杯”中国大学生算法设计超级联赛(3)

[题目链接](Search Result (hdu.edu.cn))

C Cyber Language

题目大意

一个字符串,把它的每个单词的首字母大写输出。

题解

见代码。

代码

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 2e2 + 5;
int t;
char a[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    cin.ignore();
    while (t--)
    {
        cin.getline(a, maxn);
        for (int i = 0; i < strlen(a); i++)
        {
            if (i == 0 || a[i - 1] == ' ')
                cout << char(toupper(a[i]));
        }
        cout << endl;
    }
    return 0;
}

I Package Delivery

题目大意

一个人有n个快递,每个快递被取的时间区间为[li,ri],每次最多可以拿k个快递,问最少需要取几次。

题解

贪心算法,每次考虑未取走的所有快递中 r 最小的那一天(此时不得不取),把所有l小于等于当前r且未取走的快递加入优先级队列,因为这些快递都可以取了,并按r大小排序,即先取走r较小的快递。

代码

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
typedef pair<int, int> P;
const int maxn = 1e5 + 5;
int t, n, k, res;
int ql[maxn], qr[maxn];
P p[maxn];
bool vis[maxn];
bool cmpl(const int &a, const int &b)
{
    return p[a].first < p[b].first;
}
bool cmpr(const int &a, const int &b)
{
    return p[a].second < p[b].second;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        memset(vis, 0, sizeof vis);
        priority_queue<P, vector<P>, greater<P>> q;
        cin >> n >> k;
        for (int i = 1; i <= n; i++)
        {
            cin >> p[i].first >> p[i].second;
            ql[i] = qr[i] = i;
        }
        sort(ql + 1, ql + 1 + n, cmpl);
        sort(qr + 1, qr + 1 + n, cmpr);
        res = 0;
        for (int i = 1, j = 1; i <= n; i++)
        {
            if (vis[qr[i]])
                continue;
            while (j <= n && p[ql[j]].first <= p[qr[i]].second)
            {
                q.push(P(p[ql[j]].second, ql[j]));
                j++;
            }
            for (int l = 1; l <= k; l++)
            {
                if (q.empty())
                    break;
                vis[q.top().second] = 1;
                q.pop();
            }
            res++;
        }
        cout << res << endl;
    }
}

L Two Permutations

题目大意

有两个长度为n的排列P和Q,一个长为2n的序列R,判断有几种方式可以使P和Q组成R,没有则为零。

题解

动态规划,设 f(i,j)表示 P 的前 i 项匹配上了 S,且 Pi 匹配 S 中数字 Pi 第 j 次出现的位置时,有多少种合法的方案。

转移时枚举 Pi+1 匹配哪个位置,那么 Pi 匹配的位置与 Pi+1 匹配的位置中间的那段连续子串需要完全匹配 Q 中对应的子串,使用字符串 Hash 进行判断是否相等。

注意要特判序列 R 中每个数字出现次数不都为 2 的情况,此时答案为 0。

dp:

初始化:此时Q的1,x-1和R的1,x-1需要匹配(x代表P1在R中的位置)。

if (checked(1, x - 1, 1, x - 1))
    dp[1][i] = 1;

递推:此时Q的x-i+1,y-i-1和R的x+1,y-1需要匹配(x代表Pi在R中的位置,y代表Pi+1在R中的位置)。

if (checked(x - i + 1, y - i - 1, x + 1, y - 1))
    dp[i + 1][k] = (dp[i + 1][k] + dp[i][j]) % mod;

结尾:此时Q的x-n+1,n和R的x+1,n*2需要匹配(x代表Pn在R中的位置)。

if (checked(x - n + 1, n, x + 1, n * 2))
    res = (res + dp[n][j]) % mod;

代码

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
typedef pair<int, int> P;
const int maxn = 3e5 + 5;
const int S = 233;
const int mod = 998244353;
int t, n, res;
bool ok;
int a[maxn], b[maxn], c[maxn * 2], dp[maxn][2], lc[maxn][2];
ull pb[maxn], pc[maxn * 2], p[maxn * 2];
ull ju(ull *f, int x, int y)
{
    return f[y] - f[x - 1] * p[y - x + 1];
}
bool checked(int bl, int br, int cl, int cr)
{
    if (bl > br)
        return 1;
    if (bl < 1 || br > n)
        return 0;
    return ju(pb, bl, br) == ju(pc, cl, cr);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    p[0] = 1;
    for (int i = 1; i < maxn * 2; i++)
        p[i] = p[i - 1] * S;
    cin >> t;
    while (t--)
    {
        memset(dp, 0, sizeof dp);
        memset(lc, 0, sizeof lc);
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= n; i++)
        {
            cin >> b[i];
            pb[i] = pb[i - 1] * S + b[i];
        }
        for (int i = 1; i <= n * 2; i++)
        {
            cin >> c[i];
            pc[i] = pc[i - 1] * S + c[i];
            if (!lc[c[i]][0])
                lc[c[i]][0] = i;
            else
                lc[c[i]][1] = i;
        }
        ok = 1;
        for (int i = 1; i <= n; i++)
        {
            if (!lc[i][0] || !lc[i][1])
            {
                ok = 0;
                break;
            }
        }
        if (!ok)
        {
            cout << 0 << endl;
            continue;
        }
        for (int i = 0; i < 2; i++)
        {
            int x = lc[a[1]][i];
            if (checked(1, x - 1, 1, x - 1))
                dp[1][i] = 1;
        }
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < 2; j++)
            {
                int x = lc[a[i]][j];
                for (int k = 0; k < 2; k++)
                {
                    int y = lc[a[i + 1]][k];
                    if (y <= x)
                        continue;
                    if (checked(x - i + 1, y - i - 1, x + 1, y - 1))
                        dp[i + 1][k] = (dp[i + 1][k] + dp[i][j]) % mod;
                }
            }
        }
        res = 0;
        for (int j = 0; j < 2; j++)
        {
            int x = lc[a[n]][j];
            if (checked(x - n + 1, n, x + 1, n * 2))
                res = (res + dp[n][j]) % mod;
        }
        cout << res << endl;
    }
}

K Taxi

题目大意

有n个城镇,坐标为(xi,yi),现在给一个坐标,求出最大的min(|x′−xk|+|y′−yk|,wk)。

题解

官方题解,很清楚。
在这里插入图片描述
在这里插入图片描述

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
const int Max = 0x3f3f3f3f;
int n, q, t;
struct Node
{
    int x, y, w;
    bool operator<(const Node &a) const
    {
        return w < a.w;
    }
} node[maxn];
int a[maxn], b[maxn], c[maxn], d[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        cin >> n >> q;
        for (int i = 1; i <= n; i++)
            cin >> node[i].x >> node[i].y >> node[i].w;
        sort(node + 1, node + 1 + n);
        a[n + 1] = b[n + 1] = c[n + 1] = d[n + 1] = -Max;
        for (int i = n; i >= 1; i--)
        {
            a[i] = max(a[i + 1], -node[i].x - node[i].y);
            b[i] = max(b[i + 1], -node[i].x + node[i].y);
            c[i] = max(c[i + 1], node[i].x - node[i].y);
            d[i] = max(d[i + 1], node[i].x + node[i].y);
        }
        while (q--)
        {
            int x, y;
            cin >> x >> y;
            int l = 1, r = n, mid, temp, res = 0;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                temp = x + y + a[mid];
                temp = max(temp, x - y + b[mid]);
                temp = max(temp, -x + y + c[mid]);
                temp = max(temp, -x - y + d[mid]);
                if (temp > node[mid].w)
                {
                    l = mid + 1;
                    res = max(res, node[mid].w);
                }
                else
                {
                    r = mid - 1;
                    res = max(res, temp);
                }
            }
            cout << res << endl;
        }
    }
    return 0;
}

B Boss Rush

题目大意

题解

代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值