首页 > 其他分享 >HZNU Winter Trainning STL 补题

HZNU Winter Trainning STL 补题

时间:2023-01-05 01:00:11浏览次数:65  
标签:std const STL HZNU ll cin int 补题 define

2023.01.03 HZNU Winter Trainning STL 补题

CodeForces - 4C

题意:给你n个字符串,如果某个字符串出现过,则在这个字符串后面加上1,2,3,4....以此类推

题解:利用map记录某个字符串出现次数,然后利用to_string函数即可

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
map<string, int> mp;
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            string s;
            cin >> s;
            if (mp[s] == 0)
            {
                mp[s]++;
                cout << "OK\n";
            }
            else
            {
                mp[s]++;
                cout << s + to_string(mp[s] - 1) << endl;
            }
        }
    }
    return 0;
}

CodeForces - 1526C2

题意:一个人的分数为1597,他想使他的分数增加,所以他需要打比赛,但是任何时候他不能使自己的分数低于1597,所以他需要跳过一些比赛,现在给你打的每一场能够加的分数(有可能使负数),请你计算出他最多能打几场比赛

题解:反悔贪心,优先队列实现。就是有些比赛可以假装打,后来遇到更小的比赛,直接后悔,如果比赛分数是正数直接加到sum中,如果比赛分数是负数,那么先判断如果加到sum中sum会不会<0,如果sum没有<0,那么我们直接加进去,如果<0了,我们看能不能跟现在队列里最小的元素换一下,这就是反悔的精髓,但是当时没有想明白为什么一开始是负数不行,后来仔细看题目,如果第一场是负数,他一定需要跳过,因为他任何时候的分数都不能低于1597,所以直接看代码。

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
priority_queue<ll, vector<ll>, greater<ll>> q;    //小根堆实现优先队列
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        ll sum = 0L;
        for (int i = 1; i <= n; ++i)
        {
            ll x;
            cin >> x;
            if (x >= 0)               			//x>=0直接入列
            {
                sum += x;
                q.push(x);
            }
            else
            {
                if (sum + x >= 0)           
                {
                    sum += x;
                    q.push(x);
                }
                else
                {
                    if (q.size() && q.top() < x) //会不会反悔
                    {
                        sum -= q.top();
                        q.pop();
                        sum += x;
                        q.push(x);
                    }
                }
            }
        }
        cout << q.size() << endl;
    }
    return 0;
}

CodeForces - 1490F

Dzy有一个长度为 n 的数组 a 。Dzy认为,如果存在一个数字 C ,那么数组中的每个数字都会出现 0次或 C次,那么数组就是漂亮的。为了使数组变漂亮,dzy会从数组 a 中删除一些元素

例如,如果 n=6 且 a=[1,3,2,1,4,2]a=[1,3,2,1,4,2] ,则可以进行以下操作之一使数组 a 数组更漂亮:

删除位置 2 和 5 的元素,数组 a 变为等于 [1,2,1,2][1,2,1,2];
删除位置 1 和 6 的元素,数组 a 等于 [3,2,1,4][3,2,1,4] ;
删除位置 1 、 2和 6 处的元素,数组 a 变为等于 [2、1、4][2、1、4] ;

帮助dzy确定要从数组 a 中删除的元素的最小数量,以使数组变漂亮。

t组输入,1<=t<=1e4,每行包括一个正数n1<=n<=2e5,第二行n个数ai,1<=ai<=1e9;

题解:我们先来一个引理:假设数据量n,那么最多会有多少种出现次数?我们来看一个最坏的情况1 2 2 3 3 3 4 4 4 4 5 5 5 5 5.....,直到出现n个数,所以利用等差数列求和公式,假设出现x种,列出公式

\[\frac{(1+x)*x}{2}=n \]

\[x\approx\sqrt{2n} \]

所以我们就知道了,2e5个数实际上最多就632种出现次数

回到题目,首先这道题让我们把数组每个元素出现的次数变为一样,所以与元素的值无关,定义两个map我们先把每个元素出现的次数用map1统计,用map2统计每种出现次数的组数,直接看题目给的样例

\[a: \ \ \ \ \ \ 1 \ 3 \ 2 \ 1 \ 4 \ 2 \\ map1:1出现2次,2出现2次,3出现1次,4出现1次\\ map2:出现2次的有2组,出现1次的有2组 \]

我们遍历map2对每种出现次数我们进行如下操作:如果其他出现次数比该出现次数小,我们全部删除,否则我们删除多的部分,每次对ansmin维护ans,因为最多632种出现次数,所以最多4e5数量级

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
map<ll, int> mp1, mp2;
int main(void)
{
    Zeoy;
    int t = 1;
    cin >> t;
    while (t--)
    {
        mp1.clear();
        mp2.clear();
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            ll x;
            cin >> x;
            mp1[x]++;
        }
        for (auto i : mp1)
            mp2[i.second]++;
        ll ans = inf;
        for (auto it : mp2)
        {
            ll sum = 0L;
            for (auto i : mp2)
            {
                if (i.first < it.first)
                    sum += i.first * i.second;
                else
                    sum += (i.first - it.first) * i.second;
            }
            ans = min(ans, sum);
        }
        cout << ans << endl;
    }
    return 0;
}

CodeForces - 799B

题解:因为衣服颜色就三种,直接开3个set记录每个颜色有的衣服的价格,为什么开set呢?因为顾客还想要该颜色最便宜的衣服,如果选到了衣服,就在其余两个set种将同种价格的price删掉因为一件衣服正反面两种颜色

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
ll price[N];
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        set<ll> st[4];
        for (int i = 1; i <= n; ++i)
            cin >> price[i];
        for (int i = 1; i <= n; ++i)
        {
            int x;
            cin >> x;
            st[x].insert(price[i]);
        }
        for (int i = 1; i <= n; ++i)
        {
            int x;
            cin >> x;
            st[x].insert(price[i]);
        }
        int m;
        cin >> m;
        while (m--)
        {
            int x;
            cin >> x;
            if (st[x].size())
            {
                int p = *st[x].begin();	
                cout << p << " ";
                for (int i = 1; i <= 3; ++i)	//将其他set中的相同价格全部删除
                    st[i].erase(p);
            }
            else
                cout << "-1 ";
        }
        cout << endl;
    }
    return 0;
}

Gym - 417661B 倒杨辉三角

题解:

\[\ (1\leq n\leq 11)\ \ \ \ \ \ \ \ \ (1\leq num\leq 10^6) \]

看到数据范围直接考虑next_permutation枚举,先看样例

\[\ \ \ 3\quad1\quad2\quad4\\ \quad4\quad3\quad6\\ \quad7\quad9\\ \quad16 \]

我们要知道16是可以有3 1 2 4推导出来的

\[3*C_4^0+1*C_4^1+2*C_4^3+4*C_4^4=16 \]

我们通过正杨辉三角预处理出每个元素乘以的系数index,然后进行next_permutation遍历每种情况,如果找到就退出,a数组代表枚举的数组,如果出现

\[a_1*C_n^0+a_2*C_n^1+....+a_i*C_n^{i-1}>num \]

那就说明后面[i+1,n]不用再加了,直接跳过,怎么跳过呢?我们对[i+1,n]这段序列从大到小sort一下就能跳过了,这是细节

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
int a[50][50] = {0};
int main(void)
{
    Zeoy;
    int t = 1;
    // cin >> t;
    while (t--)
    {
        int n, num;
        cin >> n >> num;
        a[1][n] = 1;
        for (int i = 2; i <= n; ++i)
            for (int j = 1; j <= 2 * n - 1; ++j)
                a[i][j] = a[i - 1][j - 1] + a[i - 1][j + 1];
        vector<int> index;
        for (int j = 1; j <= 2 * n - 1; ++j)
        {
            if (a[n][j] != 0)
                index.push_back(a[n][j]);
        }
        vector<int> v;
        for (int i = 1; i <= n; ++i)
            v.push_back(i);
        int isfind = 0;
        do
        {
            int sum = 0;
            int flag = 1;
            for (int i = 0; i < n; ++i)
            {
                sum += v[i] * index[i];
                if (sum > num)
                {
                    sort(v.begin() + i + 1, v.end(), greater<int>());
                    flag = 0;
                    break;
                }
            }
            if (flag && sum == num)
            {
                isfind = 1;
                break;
            }
        } while (next_permutation(all(v)));
        if (isfind)
        {
            for (auto i : v)
                cout << i << " ";
            cout << endl;
        }
        else
            cout << "Not Found\n";
    }
    return 0;
}

[CodeForces - 1569D ](Problem - D - Codeforces)

题解:二分+离散化+思维

我们先看垂直X轴的直线,发现如果两个点被夹在两条平行于X轴的直线之间,最短距离就不是曼哈顿距离,比如3,4和4,5,但是如果某个点和其他点再同一条垂直于X轴的直线上不产生贡献,并且处于X,Y交点处的点也不产生贡献,所以以X纵线为例,并且题目保证给的纵线坐标和横线坐标是单增的,我们可以二分找到比这个点的y坐标大的第一条Y横线,然后对Y横线加贡献,但是为了防止初始化超时,我们离散化,直接将Y的下标作为这条直线,同理Y横线的地位和X纵线等价,所以处理方式一样

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10;
int lel[N];  // 水平直线坐标 对应y轴
int ver[N];  // 垂直直线坐标 对应x轴
int numx[N]; // 代表上有几个点被夹在两条垂直x轴的直线中间
int numy[N]; // 代表上有几个点被夹在两条垂直y轴的直线中间
map<pii, int> mpx, mpy;	//代表在两线之间并且在一条直线上有几个点
int main(void)
{
    Zeoy;
    int t = 1;
    cin >> t;
    while (t--)
    {
        mpx.clear();
        mpy.clear();
        int n, m, k;
        cin >> n >> m >> k;
        for (int i = 1; i <= n; ++i)
        {
            cin >> ver[i];
            numx[i] = 0;				//离散化初始化很方便
        }
        for (int i = 1; i <= m; ++i)
        {
            cin >> lel[i];
            numy[i] = 0;
        }
        ll ans = 0L;
        for (int i = 1; i <= k; ++i)
        {
            pii p;
            cin >> p.first >> p.second;
            int x = lower_bound(ver + 1, ver + 1 + n, p.first) - ver; //落在哪条纵线上
            int y = lower_bound(lel + 1, lel + 1 + m, p.second) - lel;//落在哪条横线上
            if (p.first == ver[x] && p.second == lel[y])			//在两条线交点处
                continue;
            else if (p.first == ver[x] && p.second != lel[y])		//在纵线上
            {
                ans += (numy[y] - mpx[{x, y}]);		//离散化很方便
                numy[y]++;
                mpx[{x, y}]++;
            }
            else if (p.first != ver[x] && p.second == lel[y])		//在横线上
            {
                ans += (numx[x] - mpy[{x, y}]);
                numx[x]++;
                mpy[{x, y}]++;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

标签:std,const,STL,HZNU,ll,cin,int,补题,define
From: https://www.cnblogs.com/Zeoy-kkk/p/17026426.html

相关文章

  • stl库
    C++STL库和算法库备忘录//stack和queue都没有迭代器,只有一些相关的操作for_each(迭代器1,迭代器2,执行函数)//for_each算法函数,三个函数,只能在STL容器中使用。vector<i......
  • STL的基础操作
    1vector,变长数组,倍增的思想size()返回元素个数empty()返回是否为空clear()清空front()/back()push_back()/pop_back()begin()/end()[]支持比较......
  • 万字长文 | STL 算法总结
    本篇所有算法源码均已同步收录GitHub仓库,欢迎点个小⭐️:https://github.com/rongweihe/CPPNotes/tree/master/STL-source-code-notes​大家好,我是小贺。上一篇更新了​​ST......
  • ​硬核来袭 | 2 万字 + 10 图带你手撕 STL 关联式容器源码
    本篇已同步收录GitHub仓库,这里有小贺的源码阅读笔记:https://github.com/rongweihe/CPPNotes/tree/master/STL-source-code-notes大家好,我是小贺。鸽了好久的 STL源码系......
  • 《STL 源码剖析》学习笔记之容器(一)vector
    [图]TheContainer 2019-08-01前言侯捷大师的《STL源码剖析》,实乃一本神书,可以说也是一本很硬核的书了,不管是实验室的师兄师姐,还是牛客网上一些大佬们,都无不推荐此书,想要深......
  • stl学习之rope
    简介rope是本人在极度不想敲平衡树的情况下从朋友偶然听说的,了解之后用寥寥数行边秒杀了那道平衡树的题。笔者遂深感其强大与低调,故写笔记以纪念之。头文件与定义#inclu......
  • 《STL 源码剖析》学习笔记之容器(二)list
    [图]Theorange 2019-08-061、list概述相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次安插或删除一个元素,就配置或释放一个元素空间。因此,list对于空间......
  • The 15th Jilin Provincial Collegiate Programming Contest(补题)
    The15thJilinProvincialCollegiateProgrammingContest(补题)这次只做了4个题,感觉自己还有很多不足,加油ヾ(◍°∇°◍)ノ゙这次发现好多题都需要cin加速器,好多题不加这......
  • 寒假第一次洛谷蓝桥个人赛 题解+补题(下)
    D.灵能传输##神仙结论把前缀和应用到极致,6先考虑三个数a,b,c,进行一次变换也就是a+b,-b,c+b可见三个数之和不变,也就是s[3]不变然后之前的s[1]+b,愿称之为s[2]之前的s......
  • STL补充
    1vector,变长数组,倍增的思想1size()返回元素个数2empty()返回是否为空3clear()清空4front()/back()5push_back()/pop_back()6begin()/end()7[]8......