**第一周题解**
第五届太原理工大学程序设计竞赛新生赛(同步赛) 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可能会运行超时,没必要套太多层循环,排序后最小值一定出现在最后一位,所以只要用倒序,用一个变量存放最大的最小值,每次都比较就可以啦。
这道题唯二会做错的地方(也是本人当时在最后的时间没做对的原因)
就是
看不懂题!!!!!!!!!!!