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[n1]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[i1][j]+a[ni1]a[j],dp[i][j1]+a[ni1]a[j]),为什么是这样呢?因为 d p [ i ] [ j ] dp[i][j] dp[i][j]是由 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j]或者 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1]转移过来的,所以对于 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j],它需要删除最大值,那么由于已经删除了 i − 1 i-1 i1个最大值,那么此时再删除一个则最大值就是 a [ n − i − 1 ] a[n-i-1] a[ni1],最小值就是 a [ j ] a[j] a[j],同理对于 a [ i ] [ j − 1 ] a[i][j-1] a[i][j1],它需要删除最小值,那么由于已经删除了 j − 1 j-1 j1个最小值,此时再删除一个,最小值就是 a [ j ] a[j] a[j],最大值就是 a [ n − i − 1 a[n-i-1 a[ni1。对于 i , j i,j i,j我们同样还需要作个约束,因为最后一定是剩余一个元素的,所以删除次数不得超过 n − 1 n-1 n1,即 i + j ≤ n − 1 i+j\leq n-1 i+jn1,这也说明了最后状态就是 i + j = n − 1 i+j=n-1 i+j=n1。我们这样去处理即可,注意初始化。

  • 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;
}
posted @   unique_pursuit  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示