Codeforces Round #715 (Div. 2) A~C题解
A. Average Height
-
解题思路
水题,题目意思其实要求相邻数之和能凑出更多的偶数,那必然是奇数+奇数,偶数+偶数。将奇数和偶数分别存储起来输出即可。 -
AC代码
/**
*@filename:A_Average_Height
*@author: pursuit
*@CSDNBlog:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-04-16 22:36
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;
int t,n;
vector<int> odd,even;
void solve(){
for(int i=0;i<odd.size();i++){
cout<<odd[i]<<" ";
}
for(int i=0;i<even.size();i++){
cout<<even[i]<<" ";
}
cout<<endl;
}
int main(){
while(cin>>t){
while(t--){
cin>>n;
int temp;
odd.clear(),even.clear();
for(int i=0;i<n;i++){
cin>>temp;
if(temp%2)odd.push_back(temp);
else even.push_back(temp);
}
solve();
}
}
return 0;
}
B. TMT Document
解题思路
此题我采用模拟的方式去做这道题。我们来细细分析,按照模拟的方法,我们会去配对TMT
。用一个哈希表来记录字符出现的次数,那么在遍历字符串的过程中,我们就可以开始配对,配对的标志其实就是围绕M
这个字符,倘若我们遇到了M
,那么我们需要做的就是寻找左右边的T
,对于左边,我们毫无顾忌,找一个T
和它配对即可,即是利用哈希表中的T
数量来判断, 而对于右边,即是当我们碰到T
的时候,我们开始抉择了,如果此时的M
是大于
0
0
0的,那么这个时候我们需要配对M
,但是,并不意味着我们需要去用此时的T
来配对,因为这个T
很可能就是下一个M
左边的T
,而且右边的T
出现在哪都可以与当前的M
配对,所以我们假设它配对成功,并统计它所需要的T
,最后我们遍历完之后判断哈希表中未用的T
是否刚好是cnt
,故此题得解。需要注意的是:我们总能证明最后剩下的T
一定是在M
的右边,不然我们不会累加,注意这段程序:
if(p['M']>0){
p['M']--;//已经被配对。
//这个T可以在任何位置,存储需要的t。
cnt++;
}
AC代码
/**
*@filename:B_TMT_Document
*@author: pursuit
*@CSDNBlog:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-04-16 22:46
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;
int t,n;
string s;
map<char,int> p;
void solve(){
p.clear();
bool flag=true;
int cnt=0;
for(int i=0;i<n;i++){
p[s[i]]++;
if(s[i]=='M'){
if(p['T']==0){
flag=false;
break;
}
else{
p['T']--;
}
}
else{
if(p['M']>0){
p['M']--;
//这个T可以在任何位置,存储需要的t。
cnt++;
}
}
}
p['T']-=cnt;
if(p['T']!=0||p['M']!=0)flag=false;
if(flag)puts("YES");
else puts("NO");
}
int main(){
while(cin>>t){
while(t--){
cin>>n>>s;
solve();
}
}
return 0;
}
C. The Sports Festival
-
解题思路
这道题非常有意思。我们来看, d i = m a x ( a 1 + a 2 + . . . + a i ) − m i n ( a 1 + a 2 + . . . + a i ) d_i=max(a_1+a_2+...+a_i)-min(a_1+a_2+...+a_i) di=max(a1+a2+...+ai)−min(a1+a2+...+ai),单看这个可能难以发现什么。那么我们直接可以看 d n = m a x ( a 1 + a 2 + . . . + a n ) − m i n ( a 1 + a 2 + . . . + a n ) d_n=max(a_1+a_2+...+a_n)-min(a_1+a_2+...+a_n) dn=max(a1+a2+...+an)−min(a1+a2+...+an),这个值是已经确定了的,即是所有成员的最大速度和最小速度之差,有了这个初始值,我们就好分析了,直接从初始值下手,也就是逆着来看整个过程。为了减小这个差值,我们有两步操作可以选择:- 剔除当前最小值。
- 剔除当前最大值。
这种决策问题正好提示了我们需要使用动态规划来解决问题,即哪一步最优。我们先要表示状态,既然是剔除,我们就可以用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示剔除了 i i i个最大值, j j j个最小值的速度之差,这个值表示的意思就是累加了从 0 − > i , 0 − > j 0->i,0->j 0−>i,0−>j的速度差值。那么初始状态自然就是 d p [ 0 ] [ 0 ] = a [ n − 1 ] − a [ 0 ] dp[0][0]=a[n-1]-a[0] dp[0][0]=a[n−1]−a[0](下标从0开始)。
那么对于状态转移方程其实就已经好确定了, d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i − 1 ] [ j ] + a [ n − i − 1 ] − a [ j ] , d p [ i ] [ j − 1 ] + a [ n − i − 1 ] − a [ j ] ) dp[i][j]=min(dp[i][j],dp[i-1][j]+a[n-i-1]-a[j],dp[i][j-1]+a[n-i-1]-a[j]) dp[i][j]=min(dp[i][j],dp[i−1][j]+a[n−i−1]−a[j],dp[i][j−1]+a[n−i−1]−a[j]),为什么是这样呢?因为 d p [ i ] [ j ] dp[i][j] dp[i][j]是由 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]或者 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]转移过来的,所以对于 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j],它需要删除最大值,那么由于已经删除了 i − 1 i-1 i−1个最大值,那么此时再删除一个则最大值就是 a [ n − i − 1 ] a[n-i-1] a[n−i−1],最小值就是 a [ j ] a[j] a[j],同理对于 a [ i ] [ j − 1 ] a[i][j-1] a[i][j−1],它需要删除最小值,那么由于已经删除了 j − 1 j-1 j−1个最小值,此时再删除一个,最小值就是 a [ j ] a[j] a[j],最大值就是 a [ n − i − 1 a[n-i-1 a[n−i−1。对于 i , j i,j i,j我们同样还需要作个约束,因为最后一定是剩余一个元素的,所以删除次数不得超过 n − 1 n-1 n−1,即 i + j ≤ n − 1 i+j\leq n-1 i+j≤n−1,这也说明了最后状态就是 i + j = n − 1 i+j=n-1 i+j=n−1。我们这样去处理即可,注意初始化。 -
AC代码
/**
*@filename:C_The_Sports_Festival
*@author: pursuit
*@CSDNBlog:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-04-16 23:05
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000 + 5;
const int mod = 1e9+7;
int n;
int a[maxn];
ll dp[maxn][maxn];
void solve(){
//为了更好的处理,我们需要先对数组进行升序排列,这样可以好确定最小值和最大值。
sort(a,a+n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
dp[i][j]=1e12;//初始dp数组保留最大值。
}
}
//初始化dp数组。
dp[0][0]=a[n-1]-a[0];//这是毋庸置疑的。
for(int i=1;i<n;i++){
//只删除最大值i次
dp[i][0]=dp[i-1][0]+a[n-i-1]-a[0];//删除最大值从右边删除,那么删除之后当前最大值就是a[n-i-1];
//只删除最小值i次
dp[0][i]=dp[0][i-1]+a[n-1]-a[i];//删除最小值从左边删除,那么删除之后当前最小值就是a[i]。
}
//接下来开始进行状态转移取最优。
for(int i=1;i<n;i++){
for(int j=1;i+j<n;j++){
//i+j不得超过n次。
dp[i][j]=min(dp[i][j],dp[i-1][j]+a[n-i-1]-a[j]);//选择删除最大值
dp[i][j]=min(dp[i][j],dp[i][j-1]+a[n-i-1]-a[j]);//选择删除最小值
}
}
ll res=1e12;
for(int i=0;i<n;i++){
res=min(res,dp[i][n-i-1]);
}
cout<<res<<endl;
}
int main(){
while(cin>>n){
for(int i=0;i<n;i++)cin>>a[i];
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)