暑假多校训练营选拔赛

CF282A Bit++

题目链接

题意

其中X++,++X表示把 X 加 1 ,X–,–X表示把 X 减 1 。

思路

  1. 判断是加还是减
  2. 进行计算
  3. 最后输出结果

坑点

代码

#include
using namespace std;
int main()
{
        int n;
        cin>>n;
        int ans=0;//记录答案
        while(n--)
        {
                string s;
                cin>>s;
                if(s=="X++"||s=="++X")//判断加减
                {
                        ans++;
                }
                else{
                        ans--;
                }
        }
        cout<<ans;
        return 0;
}

总结

签到题

CF466A Cheap Travel

题目链接

题意

Ann需要搭n次地铁。她有两种票可供选择:第一种票a卢布一张,可以搭一次地铁;第二种票b卢布一张,可以搭m次地铁。问:Ann最少需要多少卢布才能搭n次地铁?

思路

  1. 要求搭n次地铁需要的最少钱
  2. 就要找单价最便宜的买,比较两种票价的大小
  3. 可以买的次数超出n次

坑点

代码

#include
using namespace std;
int main()
{
        int n,m,a,b;
        cin>>n>>m>>a>>b;
        if(float(b/m)>=a)//如果b的单价大于a的单价全全买a
        {
                cout<<a*n;
        }
        else
        {
                cout<<n/m*b+min(b,n%m*a);//否则先买b,剩余的判断是b便宜还是单买a便宜
        }
        return 0;
}

总结

简单思维,贪心

CF892B Wrath

题目链接

题意

有n个罪犯排成一排,其中第i个人拿着一个长 L i的爪子。铃声敲响时每个人都会将其前面的一些人杀掉。所有人在同一时刻杀掉其他人。也就是说,如果j=i-Li,那么第i个人将会杀掉第j 个人。现在给出每个爪子的长度,你要找出铃响之后还有多少人幸存。

思路

  1. 依次遍历每个人杀掉的人,最后计算发现会超时
  2. 可以从最后的一个人往前推,将左端点作为判断依据
  3. 判断与左端点的不同,进行计算

坑点

代码

#include
using namespace std;
const int N=1e6+10;
int a[N]; 
int main()
{
        int n;
        cin>>n;
        int ans=0;
        int minn=999999999;//初始左端点要尽可能的大
        for(int i=1;i<=n;i++)
        {
                cin>>a[i];//依次输入每个人的长度
        }
        for(int i=n;i>=1;i--)//从后往前遍历
        {
                if(minn>i)//如果当前人的位置小于左端点,这个人就是幸存的
                {
                        ans++;
                }
                minn=min(minn,i-a[i]);//更新左端点
        }
        cout<<ans;
        return 0;
}

总结

双指针、贪心,思维题

CF816B Karen and Coffee

题目链接

题意

她有 n 本食谱,第 ii 本食谱包含两个数 l_i,r_i,表示这本食谱推荐用 [l_i,r_i] 之间的温度(包含 l_i.r_i)来煮咖啡。
Karen 认为一个温度 a是可接受的当且仅当有 ≥k 本食谱推荐用 a 来煮咖啡。
Karen 有 q 个问题,每个问题用一对正整数 a_i,b_i来表示,表示她问 [a i ,b i ] 之间有多少个温度是可接受的。

思路

  1. 利用差分寻找每个点的推荐的次数
  2. 判断每个点推荐次数是否满足,放入数组,再计算前缀和,统计每个点的前缀和
  3. 最后将区间内的次数计算出

坑点

代码

#include
using namespace std;
const int N=2e6+10;
int a[N],s[N],f[N],s2[N];
int main()
{
        int n,k,q;
        cin>>n>>k>>q;
        int maxn=0;
        for(int i=1;i<=n;i++)
        {
                int l,r;
                cin>>l>>r;
                a[l]+=1;a[r+1]-=1;//利用差分将区间内的点都加1
                maxn=max(maxn,r);
        }
        for(int i=1;i<=maxn;i++)
        {
                s[i]=s[i-1]+a[i];//记录前缀和,就是统计每个点的推荐次数
        }
        for(int i=1;i<=200000;i++)
        {
                if(s[i]>=k)//遍历判断是否满足推荐次数
                {
                        f[i]+=1;//放入数组记录
                }
                else{
                        f[i]=0;
                }
        }
        for(int i=1;i<=200000;i++)
        {
                s2[i]=s2[i-1]+f[i];//计算每个点前缀和。
        }
        for(int i=1;i<=q;i++)
        {
                int a,b;
                cin>>a>>b;
                cout<<s2[b]-s2[a-1]<<endl;//判断区间内的几个点满足
        }
        return 0;
}

总结

差分,前缀和的运用

CF2A Winner

题目链接

题意

通过每轮的加减找到获胜者的名称。

思路

  1. 利用map找到最高分
  2. 判断谁先达到这个最高分
  3. 最后输出答案

坑点

  1. 如果两名或两名以上的玩家在比赛结束时都有最大的分数 m,那么其中首先获得至少 m 分的玩家胜利。

代码

#include
#include
#include
#include
using namespace std;
const int N=1e6+10;
int x[N];//记录每轮的数值
string s[N];//每个人的名字
int main()
{
        int n;
        cin>>n;
        map<string,int>mp;//记录每个人最终的分值
        map<string,int>mp2;//如有两个或两个以上都是最高分,寻找最先到达这个分数的人
        int maxn=-9999999999;
        for(int i=1;i<=n;i++)
        {
                cin>>s[i]>>x[i];
                mp[s[i]]+=x[i];
                
        }
        for(int i=1;i<=n;i++)//寻找最高分
        {
                maxn=max(maxn,mp[s[i]]);
        }
        for(int i=1;i<=n;i++)//寻找最先达到这个分数的人
        {
                mp2[s[i]]+=x[i];
                if(mp2[s[i]]>=maxn&&mp[s[i]]==maxn)
                {
                        cout<<s[i];
                        break;
                }
        }
        return 0;
}

总结

map的灵活运用

你可能感兴趣的:(算法,c++)