Codeforces Round 570 (Div. 3)题解

本文介绍了两种算法问题的解决方案。第一部分是糖果分发问题,通过排序和计数策略找到在不同种类糖果数量下能取出的最大总数。第二部分涉及子序列选择,采用广度优先搜索策略在限制条件下找出最少代价的子序列组合。这些题目考察了排序、计数和搜索等算法技巧。
摘要由CSDN通过智能技术生成

题目在这里

D - Candy Box (easy version)

题意:给出n颗糖果分别的种类号,求出在每种糖果取出的个数不同的情况下,最多能取出多少个糖果。

思路:先统计出每种糖果的个数,然后从大到小排序:
-----------eg. 2 2 1 1 1 1
则可以取出 2 1 0 0 0 0 (共3个糖果)
从最多的糖果开始取,然后依次取min(前一种糖果取的个数-1,当前糖果个数)。

:如果使用memset会超时,所以不要全部初始化,初始化一部分(1~n)就行。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

bool cmp(int a,int b)
{
	return a > b;
}

int a[200005];
int b[200005];

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		
		
		//memset(a,0,sizeof(a));
		//memset(b,0,sizeof(b));
		cin>>n;
		for(int i=0;i<=n;i++){
            a[i]=0;
        }
        for(int i=0;i<=n;i++){
            b[i]=0;
        }
		for(int i = 1;i <= n;i++)
		{
			cin>>a[i];
		}
		sort(a+1,a+n+1);
		
		int cnt = 1;
		int tmp = a[1];
		for(int i = 1;i <= n;i++)
		{
			if(a[i] == tmp)
			{
				b[cnt]++;
			}else
			{
				tmp = a[i];
				cnt++;
				b[cnt]++;
			}
		}
		if(b[cnt] == 0) cnt--;
		sort(b+1,b+cnt+1,cmp);
		int now = b[1];
		int ans = 0;
		
		for(int i = 1;i <= cnt;i++)
		{
			ans += now;
			now = max(0,min(now-1,b[i+1]));
		}
		printf("%d\n",ans);
	}
	return 0;
}

G - Candy Box (hard version)

题意:在优先糖果个数最多的情况下,优先喜爱数。最后输出该种情况的糖果个数和喜爱数。

思路:利用优先队列,用结构体存储两个变量:该种糖果的个数和喜爱数。然后循环扫描优先队列,取出头结点,如果后面的糖果个数和当前种类的糖果个数一样,那么个数–,且若喜爱数和个数一样,喜爱数也减一。

:每个test初始化的时候,不能直接memset,要初始化该次test使用了的位置。故也要开一个数组mp[i],记录糖果种类。eg. a[1] = 2,a[2] = 5…,a[n] = 12。即,有2号种类糖果、5号、…、12号种类糖果。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;

struct node {
    int cnt, like;
    bool operator < (const node &x) const {
        if (cnt == x.cnt) return like < x.like;
        else return cnt < x.cnt;
    }
};

int c[N], l[N];

int main() {
    int T; cin >> T;
    while (T--) {
        int n; scanf("%d", &n);
        map<int, int> mp;
        for (int i = 0; i < n; i++) {
            int t1, t2; scanf("%d%d", &t1, &t2);
            c[t1]++;
            if (t2) l[t1]++;
            mp[t1] = 1;
        }
        priority_queue<node> que;
        for (auto it : mp) {
            int i = it.first;
            if (c[i]) {
                node t;
                t.cnt = c[i]; t.like = l[i];
                que.push(t);
            }
        }
        int maxn = que.top().cnt - 1;
        int anscnt = que.top().cnt, anslike = que.top().like;
        que.pop();
        while(maxn > 0 && !que.empty()) {
            node t = que.top(); que.pop();
            if (t.cnt > maxn) {
                t.cnt = maxn;
                t.like = min(t.like, t.cnt);
                que.push(t);
                continue;
            }
            anscnt += t.cnt;
            anslike += t.like;
            maxn = t.cnt - 1;
        }
        cout << anscnt << ' ' << anslike << endl;
        for (auto it : mp) {
            int i = it.first;
            c[i] = 0; l[i] = 0;
        }
    }
    return 0;
}

E - Subsequences (easy version)

题意:给出一串字符串s,和容器的容量k,让你从s中挑选出k个不同的子序列(包括“ ”),最后输出最少花费,如果挑不出k个,则输出“-1”。

思路:bfs,将初始字符串入队,然后循环每减去一个字符且set中没有出现过该新字符串则加入set和队中。直到满足size >= k或队列为空时结束。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <set> 
using namespace std;

string st;
int n,k;
queue <string> q;
set <string> s;

void bfs()
{
    q.push(st);
    s.insert(st);
    while(!q.empty())
    {
        string dd=q.front();
        q.pop();
        for(int i=0 ; i<dd.size() ; i++)
        {
            string s1=dd;
            s1.erase(i,1);
            if(!s.count(s1)&&s.size()+1<=k)
            {
                q.push(s1);
                s.insert(s1);
            }
        }
    }
}
int main()
{
     cin>>n>>k;
     cin>>st;
     bfs();
     if(s.size()<k)
     {
         cout<<"-1"<<endl;
         return 0;
     }
     int ans=0;
     for(auto i :s)
     {
         ans += (st.length()-i.length());
     }
     cout<<ans<<endl;
     return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值