“深圳计算科研院杯“E起来编程暨第三届湖北省赛(BDF)

Posted K2MnO4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了“深圳计算科研院杯“E起来编程暨第三届湖北省赛(BDF)相关的知识,希望对你有一定的参考价值。

B.Mr.Maxwell and attractions

  • 题目链接:Mr.Maxwell and attractions
  • 题意:某人所在的城市有室内景观和室外景观,每种景观都有一个观赏值,每种景观在观赏时可以得到观赏值val,观赏后,其观赏值将变为原值60%(0.6val),但室外景观若在下午观赏,其观赏时只可获得本次观赏值的80%,也就是0.8val,观赏后,其观赏值一样变为原值60%(0.6val),而某人有t天可以观赏,并且必须至少有k天在下午观赏,问某人能得到的最大观赏值.
    ps:比如一室外景观观赏初值为8,若在早上观赏(第一次)则可获得观赏值8,若在下午观赏,仅可获得8 * 0.8 = 6.4的观赏值,但他们观赏后该景观的观赏值均变为8 * 0.6 = 4.8。
  • 思路:贪心 + 动态维护
  • 解析:因为室外景观在下午观赏会贬值,所以我们尽可能的都选择上午观赏,而室内景观上下午均不会贬值。
    1. 若剩余观赏天数 <= k 说明此时必须下午观赏,这时候比较当前室内景观最大的观赏值与室外景观最大的观赏值 * 0.8,谁大观赏谁;
    2. 若剩余观赏天数 > k说明上下午进行观赏均可,这时候比较当前室内景观最大的观赏值与室外景观最大的观赏值,若室内景观最大观赏值大,我们就将其放到下午观赏(室内景观上下午都不会贬值,而室外景观下午会贬值80%),若室外景观最大观赏值大则将室外景观放到上午观赏(尽可能让室外景观上午观赏)
  • 代码一:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#define debug(x) cout << "****" << x << endl
using namespace std;
int n, m, t, k;
double res = 0.0;
priority_queue<double> iq;
priority_queue<double> oq;
int main()
{
    cin >> n >> m >> t >> k;
    for(int i = 1; i <= n; i++)
    {
        double x;
        cin >> x;
        iq.push(x);
    }
    for(int i = 1; i <= m; i++)
    {
        double x;
        cin >> x;
        oq.push(x);
    }
    while(t --)
    {
        double val1 = iq.top();
        double val2 = oq.top();
        if(t < k) //必须下午参观
        {
            if(0.8 * val2 > val1) //参观室外景观
            {
                oq.pop();
                res += 0.8 * val2;
                oq.push(0.6 * val2);
            }
            else
            {
                iq.pop();
                res += val1;
                iq.push(0.6 * val1);
            }
            k --;
        }
        else //上午下午都可以参观
        {
            if(val1 >= val2) //为了不让室外景观贬值,尽可能的选择室内景观下午参观
            {
                iq.pop();
                res += val1;
                iq.push(0.6 * val1);
                k --;
            }
            else //不让室外景观贬值,让室外景观上午参观
            {
                oq.pop();
                res += val2;
                oq.push(0.6 * val2);
            }
        }
    }
    printf("%.2lf\\n", res);
    return 0;
}

  • 代码二(思路和代码一相同,只是将其拆分成上午、下午参观):
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#define debug(x) cout << "****" << x << endl
using namespace std;
const int N = 1e4 + 5;
int n, m, t, k;
double res = 0.0;
priority_queue<double> iq;
priority_queue<double> oq;
int main()
{
    cin >> n >> m >> t >> k;
    for(int i = 1; i <= n; i++)
    {
        double x;
        cin >> x;
        iq.push(x);
    }
    for(int i = 1; i <= m; i++)
    {
        double x;
        cin >> x;
        oq.push(x);
    }
    t -= k; //t-k天选择上午或下午均可(尽可能早上)
    //必须先考虑上午旅游的情况,因为室外景观在下午欣赏值会贬值
    while(t --) //室内景观上午下午都是60%喜悦值,而室外下午还会减少20%(早上为60%),所以尽可能都选早上参观
    {
        double val1 = iq.top();
        double val2 = oq.top();
        if(!k) //假如不一定要下午参观
        {
            if(val2 >= val1)
            {
                res += val2;
                oq.pop();
                oq.push(0.6 * val2);
            }
            else
            {
                res += val1;
                iq.pop();
                iq.push(0.6 * val1);
            }
        }
        else
        {
            if(val2 >= val1)
            {
                res += val2;
                oq.pop();
                oq.push(0.6 * val2);
            }
            else if(val1 > val2)
            {
                res += val1;
                iq.pop();
                iq.push(0.6 * val1);
                t ++;
                k -- ;//既然室内景观比室外的欣赏值高,那干脆放到下午去看,反正欣赏值都一样,尽可能不让室外景观贬值
            }
        }
    }
    while(k --) //剩下的k天必须下午去
    {
        double val1 = iq.top();
        double val2 = oq.top();
        if(0.8 * val2 >= val1)
        {
            res += 0.8 * val2;
            oq.pop();
            oq.push(0.6 * val2);
        }
        else
        {
            res += val1;
            iq.pop();
            iq.push(0.6 * val1);
        }

    }
    printf("%.2lf\\n", res);
    return 0;
}

D.WA

  • 题目链接:WA
  • 题意:给出一个字符串,有k次操作可以将不是a的字符替换成a,问操作后的字符串最多能有几个\'aa\'的子串
  • 思路:贪心 + 模拟
  • 解析:先找出有多少个ax...xa这样的序列,从小到大按起点为a终点也为a的序列长度排序,从长度最小的序列将不是a的字符替换成a,最后序列若两个a中没有夹有其他字符并且还有可以将字符替换成a的次数,那么则找到这个xx..aaa(不一定是3个a可能1个、2个)..xx的序列,从第一个a的左侧和最后一个a的右侧依次将字符替换成a即可。
  • 代码:
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N = 5e5 + 5;
struct Node
{
    int b = 0, e = 0, num = 0;
}p[N];
int n, k, cnt = 0, res = 0, acnt = 0;
string str;
bool cmp(Node a, Node b)
{
    return a.num < b.num;
}
int main()
{
    cin >> n >> k;
    cin >> str;
    int flag = 0;
    for(int i = 1; i < str.length(); i++)
    {
        if(!flag && str[i] != \'a\' && str[i-1] == \'a\')
        {
            p[++cnt].b = i;
            p[cnt].num ++;
            flag = 1;
        }
        else if(flag && str[i] == \'a\')
        {
            p[cnt].e = i - 1;
            flag = 0;
        }
        else if(flag && str[i] != \'a\')
            p[cnt].num ++;
    }
    if(p[cnt].e == 0) cnt --; //特判最后一个区间是不是没有被一个a包住
    if(cnt > 0) //判断是否有被两个a包围的区间
    {
        sort(p + 1, p + 1 + cnt, cmp); //将被两个a包住区间长度从小到大排序,从最小的开始替换a(可能为aaa,所以判断cnt)
        for(int i = 1; i <= cnt; i++)
        {
            if(!k) break;
            for(int j = p[i].b; j <= p[i].e; j++)
            {
                str[j] = \'a\';
                k --;
                if(!k) break;
            }
        }
    }
    if(k) //剩余k说明当前所有的a肯定是连在一起的
    {
        int afpos = -1; //第一个a
        int alpos = -1; //最后一个a
        for(int i = 0; i < str.length(); i++)
        {
            if(str[i] == \'a\' && afpos == -1) afpos = i;
            else if(str[i] == \'a\' && afpos != -1) alpos = i;
        }
        if(acnt == 1) alpos = afpos; //只有一个a起始点与终点一致
        for(int i = afpos - 1; i >= 0 && k; i--) //从第一个a开始往左更新
        {
            str[i] = \'a\';
            k --;
        }
        for(int i = alpos + 1; i < str.length() && k; i++) //从最后一个a往右更新
        {
            str[i] = \'a\';
            k --;
        }
    }
    for(int i = 1; i < str.length(); i++)
            if(str[i] == \'a\' && str[i-1] == \'a\') res ++;
    cout << res << endl;
    cout << str << endl;
    return 0;
}

/*
5 2
bbaac
*/


E.Meet in another world, enjoy tasty food!

  • 题目:Meet in another world, enjoy tasty food!
  • 题意:有n个人在排队,每个人的忍耐值是xi,但现在每隔一段时间就会有一个操作:从第1个人-> 第n个人,每个人的忍耐值将会减掉它所在的位置号(从1开始到n),若此时xi <= 0,则此人离开队列,并且它之后的所有人将向前移动一个位置,而此时它身后的人忍耐值减掉的值将是新的位置号,最后要求输出依次离开的人的原位置编号.
  • 思路:思维 + 模拟区间维护
  • 解析:首先每个人实际能存活的操作轮数为res = ceil(xi / 当前位置号pos),然后找出最小值(若相等,则编号小的先离开),此时需要对离开的人前后的人([1, pos-1], [pos+1, n]这两个区间)进行维护:
    1. 区间为:[1, pos-1]
      实际上这个区间的人也进行res次循环操作,所以其忍耐值xi -> xi - res * 其当前位置号,但其需要离开的最少操作循环次数为:ceil(xi / 当前位置号pos) + 1,加1的原因其实是因为此轮其实已经遍历经过[1, pos-1],而[pos + 1, n]仍未遍历完成
    2. 区间为:[pos+1, n]
      实际上这个区间的人仅进行(res - 1)次循环操作,所以其忍耐值xi -> xi - (res - 1) * 其当前位置号,然后需要将其向前移动一位,其需要离开的最少操作循环次数为:ceil(xi / 新的当前位置号)
  • 代码:
#include<iostream>
#include<cmath>
using namespace std;
const int N = 1005;
typedef long long ll;
int n;
struct Node
{
    int id = 0; //初始编号
    double val = 0;
    ll t = 0; //需要循环t次将离开队伍
}a[N];
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i].val;
        a[i].id = i;
        a[i].t = ceil(a[i].val / (double)i);
    }
    while(n)
    {
        int pos = 1; //当前最先离开的人的位置
        double res = a[1].t; //当前最先离开的人需循环的总次数
        for(int i = 1; i <= n; i++) //找出当前最先离开队伍的人(循环次数一样编号小的先离开)
        {
            if(a[i].t < res)
            {
                pos = i;
                res = a[i].t;
            }
        }
        cout << a[pos].id << " "; //输出离开的人编号
        for(int i = 1; i <= pos - 1; i++) //维护1 - (pos - 1)的人
        {
            a[i].val -= i * res; //总共循环res次
            a[i].t = ceil(a[i].val / (double)i) + 1; //+1:当前起点从pos开始
        }
        for(int i = pos; i <= n - 1; i++) //维护(pos + 1) - n的人
        {
            a[i+1].val -= (i + 1) * (res - 1); //总共循环res-1次
            a[i].val = a[i+1].val; //位置向前移
            a[i].id = a[i+1].id; //编号不变
            a[i].t = ceil(a[i].val / (double)i);
        }
        n --; //人数不断减少
    }
    return 0;
}

以上是关于“深圳计算科研院杯“E起来编程暨第三届湖北省赛(BDF)的主要内容,如果未能解决你的问题,请参考以下文章

“盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛 E

“盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛题解&&源码A,水,B,水,C,水,D,快速幂,E,优先队列,F,暴力,G,贪心+排序,H,STL乱搞,I,尼姆博(

“今日头条杯”首届湖北省大学程序设计竞赛(网络同步赛 )--B. Salty Fish Go!

CCPC2019河北省赛 E.Paper Plane Fly Away

2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛)-正式赛 部分题解

第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组思考+总结