第一周题解

文章介绍了几道程序设计竞赛题目,包括太原理工大学新生赛的G题和牛客练习赛的题目。主要内容涉及利用动态规划求解最高得分策略,以及代码优化技巧,如滚动数组的应用,以节省空间。同时,文章强调了理解和解析题目是解题的关键。
摘要由CSDN通过智能技术生成

第五届太原理工大学程序设计竞赛新生赛(同步赛) G题

链接:https://ac.nowcoder.com/acm/contest/55352/G
来源:牛客网

题目描述

举办一场新生赛还需要几个签到题,Hammer 决定去寻找境外势力的帮助。经过打听,Hammer 得知 AGC 里全是签到题,于是他报名了下一场 [AtCoder Grand Contest] ,打算直接从里边搬两个题当做新生赛的签到题。在 contest 进行前,Hammer 先去了解了一下 Atcoder 的比赛规则。

一场 Atcoder 比赛会持续 T 分钟,共有 n 道题,在你 AC 第 i题后可以得到 si 的分数。比赛以总分数来进行排名,若总分数相同则以最后一次有效 AC 时间排名,越早者排名越靠前。(实际比赛会以AC之前的错误提交来计算罚时,因为Hammer 是一个良心的出题人,所以在这里我们无需考虑罚时。)

Hammer 深知自己的水平高低,对于每道题目看一眼题目名字就知道自己 AC 这道题需要多少分钟(可以假设 Hammer 拿到了时光机器,早已提前看过了题,比赛中无需再花费时间看题)。请你计算 Hammer 如果按照能获得尽可能高排名的方式去答题,最终的得分会是多少。

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例:

在这里插入图片描述

两种代码解法:
1.常规dp解法
2.滚动数组
我们先展示常规dp解法 :

代码展示

#include <bits/stdc++.h>
using namespace std;
int time[10005];//time存放每道题所需要做的时间
int worth[10005];//worth存放每道题的分值
int dp[10005][10005];
int main()
{
    int n,v;
    cin>>n>>v;
    for(int i=1;i<=n;i++)
        cin>>worth[i]>>time[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=v;j++)
            {
                if(time[i]>j)
                    dp[i][j]=dp[i-1][j];
                else
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-time[i]]+worth[i]);
            }
    }
    printf("%lld",dp[n][v]);
}
```cpp
  • 创建二维数组存放每一次的数值,保证每一个数值都是到该行为止目前最大的数值

  • 如果所需时间 time[i] > j 的数值,直接将【前一行的该列数值 】dp[i-1][j] 挪下来即可

  • 反之

  • 比较【前一行的该列数值 】dp[i-1][j] ,【j与所需时间差值的代表数和该时间代表的数值】dp[i-1][j-time[i]]+worth[i]),存放较大的数值。

  • 全部遍历完,打印即可。

#include<bits/stdc++.h>
using namespace std;
int f[10005],worth[25],time[25];
int main()
{
	int n,m,i,j;
	cin>>n>>m;
	for(i=0;i<n;i++)
	   cin>>worth[i]>>time[i];
	for(i=0;i<n;i++)
	   for(j=m;j>=time[i];j--)
	       if(f[j-time[i]]+worth[i]>f[j])
	       		f[j]=f[j-time[i]]+worth[i];
	cout<<f[m];
	return 0;
}
  • 简单来说,滚动数组就是用新的数据不断覆盖旧的数据量来减少空间的使用,所以仅定义一维数组即可,跟刚才的思维逻辑差不多,只不过是dp常规解法的优化而已

  • 唯一不一样的地方,就是第11行的遍历是从后往前的,原因很简单:

  • 当某个位置更新数据时,一定会是先调用其位置之前的旧数据,然后再将当前位置更新覆盖掉原来的旧数据。

  • 如果从前往后的话遍历的话,所调用的数据一定是新数据,答案便不一定是正确的了。

牛客练习赛110

链接:https://ac.nowcoder.com/acm/contest/54129/A
来源:牛客网

题目描述

在这里插入图片描述

输入描述

在这里插入图片描述

输出描述

在这里插入图片描述

示例

在这里插入图片描述

代码展示

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n;
	string ss;
	cin>>ss;
	long long l1=-1,l4=-1,ans=0;
	for(int i=0;ss[i];i++)
	{
		if(ss[i]=='1') l1=i;
		else if(ss[i]=='4') l4=i;
		ans+=i-min(l1,l4);	
	}
	cout<<ans;
}
  • ans每一次存放的都是前 i 个字符组成的符合要求的子串数量。

  • L1和L4每次存放的都是最后一次出现1和4的位置

  • 情况1:

  • 若到第 i 次循环的时候只出现了4或1 :

  • 4和1最后位置的最小值依然是-1,而 i - (-1)是加上坐标 i 本身的一共字串个数。

  • 例:2367819243
    当 i = 6 时, L1 = 5,L4 = -1,所以当字符为 ’ 9 ’ 时, 字符 ’ 9 ’ 往前的子串一共有7个,再加上之前的ans即可。

  • 情况2:

  • 若到第 i 次循环时,1或4都没出现:

  • 同理可得,跟情况1 一样

  • 情况3:

  • 若到第 i 次循环的时候4和1都出现了:

  • 4和1的最小位置用 i 作减法,即可

  • 例:2367819243

  • 当 i = 9 时,L1 = 5,L4 = 8,所以当字符为 ’ 3 ’ 时,从后往前捋,3,34,342,3429,所以一共有4个,而再往前就不符合规矩啦,再往前就包含1和4了,所以就是这样做滴。

22练习赛 - C题

链接:https://vjudge.net/contest/553891
来源:Virtual Judge

题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
网上翻译:
在这里插入图片描述

输入描述

在这里插入图片描述

输出描述

在这里插入图片描述

示例

在这里插入图片描述

代码展示

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;int a[n];
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        if(n==1)
            cout<<a[0]<<endl;
        else
        {
            sort(a,a+n,greater<int>());
            int max_=a[n-1];
            for(int j=n-1;j>0;j--)
            {
                max_=max(max_,a[j-1]-a[j]);
            }
            cout<<max_<<endl;
        }
    }
    return 0;
}
	 				  	 		  					  				     	

这道题思路不复杂,
找出每次数组的最小值,数组的每个元素都减这个最小值,紧接着就一直减减减,每次不是都有一个最小值嘛,输出这些最小值哪个最大就行

但是测试点3可能会运行超时,没必要套太多层循环,排序后最小值一定出现在最后一位,所以只要用倒序,用一个变量存放最大的最小值,每次都比较就可以啦。
这道题唯二会做错的地方(也是本人当时在最后的时间没做对的原因)
就是

看不懂题!!!!!!!!!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值