ACM2021辽宁省赛:CDEFGILM

ACM2021辽宁省赛:CDEFGILM

C-传染病统计_

问题解析

一开始没注意到n只有8。。。当1e5的范围来写的。

这题就是说,所有相隔距离小于等于2的是一个集体,然后我们要选一个集体感染病毒,问最多的感染人数和最小的感染人数。

先对所有人进行升序排序(因为不知道给的输入是不是有序的)。然后遍历一遍数组,把相隔距离不超过2的都当作一个集体,如果B和A的距离超过2了,说明B是另一个集体,我们重新计算。在此过程中维护集体人数的最大值和最小值。

分别输出最小值和最大值即可。

时间复杂度:(T*nlogn);

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 1e6 + 50;

void solve()
{
    int n;
    cin >> n;
    vectorv(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    sort(v.begin(), v.end());
    int mx = 0, mn = 1e9, len = 1;
    for (int i = 1; i < n; i++)
    {
        if (v[i] - v[i - 1] <= 2)len++;
        else
        {
            mx = max(mx, len);
            mn = min(mn, len);
            len = 1;
        }
    }
    mx = max(mx, len);
    mn = min(mn, len);
    cout << mn << " " << mx << endl;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

D-阿强与网格

问题解析

一开始下意识的想BFS,后来发现根本不用那么麻烦(而且也过不了)。

题目已经给定了我们每次操作所花成本,我们可以根据x和y的大小,与网格的形状直接计算得出结果,为了方便,我们认定n比m大:

  1. 如果网格是n *1的形状,此时显然只能用x的方式移动,成本为:*(n-1)x;
  2. 因为y走一步等于x走两步,所以如果x的两倍小于等于y,我们直接用x走,成本为:*(n+m-2)x

剩下的情况,我们显然是能用y走就用y走,问题是y该怎么走呢?

一开始想着先对角线移动到底部,然后剩下的用x平移过去:(红色路线)

ACM2021辽宁省赛:CDEFGILM_第1张图片

后来发现,其实剩下的位置也是可以斜着走的:(蓝色路线)

ACM2021辽宁省赛:CDEFGILM_第2张图片

只不过这么走有约束,即到了底边后,距离终点的距离如果是奇数,则会停在终点的前一格,而这时我们只能用x走了:(橙色路线)

ACM2021辽宁省赛:CDEFGILM_第3张图片

那么对于其它的情况:我们先走m次y,如果距离终点的距离:n-m是奇数,我们走了(n-m-1)次y后,还要走一次x,成本为:m*y+(n-m-1) * y+x;如果n-m是偶数,我们直接全走y即可,成本为:m*y+(n-m) * y.

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 4e5 + 50;

void solve()
{
    int n, m, x, y,ans;
    cin >> n >> m >> x >> y;
    //为了方便,我们保证n比m大
    if(n> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

E-生活大爆炸

问题解析

这道题主要思路就是我们高中就学过的组合数计算。

男生有n人,女生有m人,需要组成总人数为t的队伍,其中男生人数不能少于4人,女生人数不能少于1人。

那么可能的排列组合就是:4个男生和t-4名女生,5个男生和t-5名女生,……,t-1名男生和1名女生。

对于第一个组合来说,就是n个男生中随机选出4个,搭配上m个女生中随机选出t-4个,即:C(n,4)*C(m,t-4)。其余的以此类推,把所有的组合数相加即可。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 4e5 + 50;

int C[70][70];
void init()
{
    for (int i = 0; i <= 70; i++)
        for (int j = 0; j <= i; j++) {
            if (!j)
                C[i][j] = 1;
            else
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
}

void solve()
{
    int n, m, t;
    cin >> n >> m >> t;
    init();
    int res = 0;
    for (int i = 4; i <= min(n, t - 1); i++)
    {
        res += C[n][i] * C[m][t - i];
    }
    cout << res;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

F-Capslock

问题解析

只要看第2到第n个字符是不是都是大写字母,如果是,遍历一遍数组把大写字母变成小写字母,把小写字母变成大写字母。如果不是,直接原样输出。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 1e6 + 50;

void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    bool flag = true;
    for (int i = 1; i < n; i++)
    {
        if (!(s[i] >= 'A' && s[i] <= 'Z'))
        {
            flag = false;
            break;
        }
        
    }
    if (!flag)
    {
        cout << s << endl;
        return;
    }
    if (s[0] >= 'A' && s[0] <= 'Z')
    {
        s[0] += 32;
    }
    else s[0] -= 32;
    for (int i = 1; i < n; i++)
    {
        s[i] += 32;
    }
    cout << s;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

G-字节类型

问题解析

可以用字符串来接收输入。

根据字符串的长度和转换成整数后的大小进行比较即可。

如果担心longlong会炸,就用unsigned long long来存储结果。字符串长度要是大于19,直接就是BigInteger。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 1e6 + 50;

ull check(string s)
{
    ull num = 0;
    int n = s.size();
    for (int i = 0; i < n; i++)
    {
        num *= 10;
        num += s[i] - '0';
    }
    return num;
}

void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    if (n > 19)cout << "BigInteger" << endl;
    else if (n <= 3)
    {
        int num = stoi(s);
        if (num <= 127)cout << "byte" << endl;
        else cout << "short" << endl;
    }
    else if (n <= 5)
    {
        int num = stoi(s);
        if (num <= 32767)cout << "short" << endl;
        else cout << "int" << endl;
    }
    else if (n <= 10)
    {
        int num = stoi(s);
        if (num <= 2147483647)cout << "int" << endl;
        else cout << "long" << endl;
    }
    else if (n <= 19)
    {
        ull num = check(s);
        if (num <= 9223372036854775807)cout << "long" << endl;
        else cout << "BigInteger" << endl;
    }
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

I-完美主义

问题解析

开一个单点修改+区间查询的线段树。

  • st[k]表示,st[k]为true,表示当前区间是完美区间,反之不是;
  • right[k]表示当前区间最右边的元素;
  • left[k]表示当前区间最右边的元素;

对于一个区间,如果它的左右子区间的st都为true,且左区间的right小于等于右区间的left,那么当前区间也是一个true;反之是false。由此类推,我们每次更新时,只要维护区间的left和right,再根据他们的大小判断st的值,就可以快速得出当前区间是否是完美的。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 4e5 + 50;

int myleft[4 * N], myright[4 * N], a[N];
bool st[4 * N];
void build_tree(int k, int l, int r)
{
    if (l == r)
    {
        myleft[k] = a[l];
        myright[k] = a[l];
        st[k] = true;
        return;
    }
    int m = (l + r) / 2;
    build_tree(k + k, l, m);
    build_tree(k + k + 1, m + 1, r);
    if (myleft[k + k + 1] >= myright[k + k])
    {
        st[k] = st[k + k] && st[k + k + 1];
    }
    else st[k] = false;
    myleft[k] = myleft[k + k];
    myright[k] = myright[k + k + 1];
}

void revise(int k, int l, int r, int x, int y)
{
    if (l == r)
    {
        myleft[k] = y;
        myright[k] = y;
        return;
    }
    int m = (l + r) / 2;
    if (x <= m)revise(k + k, l, m, x, y);
    else revise(k + k + 1, m + 1, r, x, y);
    if (myleft[k + k + 1] >= myright[k + k])
    {
        st[k] = st[k + k] && st[k + k + 1];
    }
    else st[k] = false;
    myleft[k] = myleft[k + k];
    myright[k] = myright[k + k + 1];
}

//对于pair>,first表示这个区间的st。
//second。first是left;second。second是right
pair> calc(int k, int l, int r, int x, int y)
{
    if (l == x && r == y)return { st[k],{myleft[k],myright[k]} };
    int m = (l + r) / 2;
    if (y <= m)return calc(k + k, l, m, x, y);
    else
        if (x > m)return calc(k + k + 1, m + 1, r, x, y);
        else
        {
            auto ans1 = calc(k + k, l, m, x, m);
            auto ans2 = calc(k + k + 1, m + 1, r, m + 1, y);
            if (ans1.first == false || ans2.first == false)
            {
                return { false,{-1,-1} };
            }
            else
            {
                if (ans1.second.second <= ans2.second.first)
                {
                    return { true,{ans1.second.first,ans2.second.second} };
                }
                else return { false,{-1,-1} };
            }
        }
}

void solve()
{
    int n, m, t, x, y;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)cin >> a[i];
    build_tree(1, 1, n);
    while (m--)
    {
        cin >> t >> x >> y;
        if (t == 1)
        {
            revise(1, 1, n, x, y);
        }
        else
        {
            if (calc(1, 1, n, x, y).first)
            {
                cout << "Yes" << endl;
            }
            else cout << "No" << endl;
        }
    }
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

L-神奇的回答

问题解析

大于18的输出18,小于等于18的原样输出。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 1e6 + 50;

void solve()
{
    int n;
    cin >> n;
    if (n >= 18)cout << 18 << endl;
    else cout << n << endl;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

M-比赛!

问题解析

拓扑排序。

根据每个人的回答,我们把它看成“A:BC”,转化成关系就是,B->A->C。我们以此来建图,同时记录每个点的入度。

建图之后来一遍拓扑排序,用一个字符串s来存储结果,因为入度为0的点,相当于它的前面没有别的选手,我们就可以把它加入到字符串的尾部。

如果拓扑排序后,所有的选手都在字符串里了,我们就把他输出;否则输出No Answer。

AC代码

#include
using namespace std;
#include
#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pairPII;
const int N = 4e5 + 50;

vectorgraph[300];
unordered_mapmymap;
void solve()
{
    int n;
    cin >> n;
    string s;
    for (int i = 1; i <= n; i++)
    {
        cin >> s;
        graph[s[2]].push_back(s[0]);
        graph[s[0]].push_back(s[3]);
        if (!mymap.count(s[2]))mymap[s[2]] = 0;
        mymap[s[0]]++;
        mymap[s[3]]++;
    }
    queueque;
    string str;
    for (auto& i : mymap)
    {
        if (i.second == 0)
        {
            str += i.first;
            que.push(i.first);
        }
    }
    
    if (que.size() == 0)
    {
        cout << "No Answer" << endl;
        return;
    }
    while (!que.empty())
    {
        auto t = que.front();
        que.pop();
        bool flag = false;
        for (auto i : graph[t])
        {
            mymap[i]--;
            if (mymap[i] == 0)
            {
                str+=i;
                que.push(i);
            }
        }
    }
    if(mymap.size()!=str.size())
    {
        cout << "No Answer" << endl;
    }
    else cout << str << endl;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}

你可能感兴趣的:(笔记,c++,算法,acm)