2023牛客暑期多校训练营4补题题解1

目录

一、L题目大意和输入输出要求

二、解决思路

1.浅谈

2.代码实现

AC代码

总结

第二部分

F题题解

一、题目大意和输入输出描述

输入样例:

输出样例:

二:代码实现:

存储数据:

模拟票人的过程:

AC代码:

总结:



前言

为简单的题目写一些题解。

一、L题目大意和输入输出要求

有n行m列个灯泡,起初都是关闭状态,执行k次操作,每次操作为某行或者某列关闭,例如:

row 1 on
column 4 on

输入样例:

3 4 4
row 1 on
column 4 on
row 3 on
column 2 off

输出样例:

7

二、解决思路

1.浅谈

在比赛的时候我想得是用两个数组模拟行和列,但一直苦于灯的开关状态可能会被后面的操作给覆盖掉导致无法实现,所以可以采用倒着模拟的方法,因为灯的开关状态时由最后一次灯的状态所决定。

2.代码实现

我们需要将输入的的操作存起来,用一个结构体数组即可。

struct node
{
    ll x,y,z;
}; 
node a[N];
for(int i=1;i<=q;i++){
        string s,s1;
        ll l;
        cin>>s>>l>>s1;
        if(s!="row")
        a[i].x=1;//1是表示列操作
        a[i].y=l;//y来储存是对第几行或列进行操作
        if(s1=="on")
            a[i].z=1;//当输入的命令为开时,z置为1
    }

模拟过程

for(int i=q;i>=1;i--)
    {
        if(a[i].x==0)
        {
            if(f1[a[i].y])continue;//访问过就模拟下一次操作
            f1[a[i].y]=1;//因为是倒着模拟的所以只要访问过一次就不需要访问该行
            if(a[i].z)
                ans+=m;//如果是开着的操作,就对该行进行计数,算开灯的数目
            n--;//无论开灯还是关灯,该列的状态已经定了下来,直接减去一行
        }
        else{
            if(f2[a[i].y])continue;
            f2[a[i].y]=1;//因为是倒着模拟的所以只要访问过一次就不需要访问该行
            if(a[i].z)
                ans+=n;
            m--;
        }
    }
    cout<<ans;//输出处于开灯的灯的数目

AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+5;
struct node
{
    ll x,y,z;
}; 
node a[N];
ll f1[N],f2[N]; 
int main()
{
    ll n,m,q,sum,i;
    cin>>n>>m>>q;
    ll ans=0;
    for(int i=1;i<=q;i++)
    {
        string s,s1;
        ll l;
        cin>>s>>l>>s1;
        if(s!="row")
        a[i].x=1;//1是表示列操作
        a[i].y=l;
        if(s1=="on")
            a[i].z=1;
    }
    for(int i=q;i>=1;i--)
    {
        if(a[i].x==0)
        {
            if(f1[a[i].y])continue;
            f1[a[i].y]=1;
            if(a[i].z)
                ans+=m;
            n--;
        }
        else{
            if(f2[a[i].y])continue;
            f2[a[i].y]=1;
            if(a[i].z)
                ans+=n;
            m--;
        }
    }
    cout<<ans;
    return 0;  
}

总结

以上就是今天写的内容,本文仅简单写了L题的解决。

第二部分

F题题解

一、题目大意和输入输出描述

每个人的政治倾向用数字给予量化,并且数字的代表左倾和右倾,数字越大就是越右倾,反之亦然,并且对于每一个输出数据,都要进行m-1轮投票,在一轮中每个人只会投给与自己政治倾向相差最大的那个(不会是自己),如果政治倾向差值相等就投票最右倾的那个,题目保证这n个人的政治倾向都是不同的。最后输出那个最后存活者的下标。

输入样例:

第一行包含一个正整数n,表示候选数。第二行包含n个不同的整数,表示每个候选人的政治倾向。

4
5 1 8 10

输出样例:

1

二:代码实现:

浅谈:我在赛后看了一下题目,本着以为是考我二分的吧,但是并不是这样,因为一轮才只淘汰一个人,我是看了题解才看懂了这个题,虽然只是一个简单的模拟,但还是学到了不少。

 因为最后要输出投票者的下标,但还要对数据的值进行操作,所以采用一种新的容器pair,我刚开始也不知道,但和其他的没什么太大的区别,所以很容易可以接受。

pair基础知识学习链接:pair学习链接

即使不去看的话也是可以看懂的哦!

存储数据:

有n个人,用pair建立一个数组,并为它赋值上下标,最后在根据政治倾向进行排序。

pair<int ,int> shu[1000005];
for(int i=1;i<=n;i++){
        cin>>shu[i].first;
        shu[i].second=i;//第二个数据就是代表着下标
    }
sort(shu+1,shu+1+n);
模拟票人的过程:
    int l=1,r=n;
    for(int i=n,j=(n+1)/2;i>=2;i--){//i代表着还存在的人数,
        int mid1=(shu[r].first-shu[j].first)-(shu[j].first-shu[l].first);
//mid1代表着最大值和中间值的差值减去中间值和最小值的差值
        if(i%2==0)//差值为偶数
        {
            int mid2=(shu[r].first-shu[j+1].first)-(shu[j+1].first-shu[l].first);
/*mid2的作用为当人数为偶数时,需要考虑最中间的两个,理由我不再赘述,可得结论,只有两个都投最小值的那个才会票最小的,否则会票最大的*/
            if(mid2>=0||mid1>=0){
                r--;
            }
            else{
                l++;
                j++;
            }
        }
        else//如果为奇数只用考虑mid1,大于等于0票最大值,否则相反
        {
            if(mid1>=0){
                r--;
                j--;
            }
            else{
                l++;
            }
        }
    }
cout<<shu[l].second;//只剩两个人时,右倾的会被淘汰掉。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
pair<int ,int> shu[1000005];
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0); 
    cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>shu[i].first;
        shu[i].second=i;
    }
    sort(shu+1,shu+1+n);
    int l=1,r=n;
    for(int i=n,j=(n+1)/2;i>=2;i--){
        int mid1=(shu[r].first-shu[j].first)-(shu[j].first-shu[l].first);
        if(i%2==0)
        {
            int mid2=(shu[r].first-shu[j+1].first)-(shu[j+1].first-shu[l].first);
            if(mid2>=0||mid1>=0){
                r--;
            }
            else{
                l++;
                j++;
            }
        }
        else
        {
            if(mid1>=0){
                r--;
                j--;
            }
            else{
                l++;
            }
        }
    }
    cout<<shu[l].second;
    return 0; 
}
//我真的不玩原神

总结:

我把为什么要这样写的原因加下注释里了,写了F和L的题解。

如有错误,欢迎指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值