0


2022 Robocom世界机器人开发者大赛 CAIP编程赛道 本科组-省赛 挨打记录+题解

2022 Robocom CAIP编程赛道 省赛题解

今天刚打完的省赛…马上退役的大三菜狗来摸一发题解,大佬勿喷QAQ。

今年和去年不同,五道题100分,可以说1、2、3的45分完全是白给的,4是真的恶心,5有点思维题的感觉,想出来就简单,想不出来就很难。

由于题目已经不记得了,只有代码能摸摸鱼发一下这样子…

第一题

题目大意是有

n

天,每天存

a[i]

元钱,钱有上限

K

,如果钱要超出上限了就去花了再存,问一共花了多少次钱?

很简单,根据题目模拟即可,维护当前的钱数

now

,如果加上当天存的钱超过了上限就去花一次。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

LL n,m;
LL a[1010]; 

int main()
{
    cin>>n>>m;
    LL now=0;
    LL ans=0;
    for (int i=1;i<=n;i++)
    {
        LL x;cin>>x;
        if (now+x>m)
        {
            ans++;
            now=0;
        }
        now+=x;
    }
    cout<<ans;
    return 0;
}

第二题

题目大意是病人要吃

n

种药,吃一共

m

次,每种药要相隔

t[i]

天才能吃第二次。给出

m

次记录,每次给出当前天的时间

t

和当天吃的药的数量

k

,然后是这些药的种类。如果能吃就吃,不能吃则输出

Don't take X at Y!

,其中

X

是药的种类,

Y

是当前的天数。

也是很简单的模拟题,根据题意直接模拟就完事了= =

唯一的坑点是第一次吃药是必定成功的,而如果不处理上次吃药的时间,第一次吃药也有可能会失败,我们只要把last数组初始化成负无穷即可。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N=1010;

int n,m;
LL t[N],last[N];

int main()
{
    cin>>n>>m;
    
    for (int i=1;i<=n;i++)    cin>>t[i];
    
    memset(last,-0x3f,sizeof(last));
    
    while(m--)
    {
        int now,k;cin>>now>>k;
        while(k--)
        {
            int x;cin>>x;
            if (now-last[x]<t[x])
            {
                printf("Don't take %d at %d!\n",x,now);
                continue;
            }
            else
            {
                last[x]=now;
            }
        }
    }
    
    return 0;
}

第三题

题目大意是给定一个字符串,字符串由一些项和加减号构成,这些项要么是

X

的数字类型,要么是

XdY

的骰子类型。数字类型代表直接对结果加或减,骰子类型代表投出

X

Y

面骰子,骰子的结果可能是1~Y,问表达式最终的最小结果和最大结果是什么,并输出每种骰子需要多少个。

这个题就稍微有点难度了,其实也是模拟题,考验大家对字符串的操作。

我们可以将整个字符串分成由加减号隔断的数个项,这些项如果是数字类型,那么他们对结果的影响是恒定的;如果是骰子类型,那么我们就要看前面的加减号是什么了:如果是加号,那么当投出的都为1的时候可以对应出最小结果,投出的都为Y的时候可以对应出最大结果;反之,如果是减号,那么投出的都为Y的时候可以对应出最小结果,投出的都为1的时候可以对应最大结果。

综上所述,我们只需要分出这些项之后分类讨论即可。由于我们是将这些项用加减号隔开,那么我们可以在读到加减号的时候对结果进行计算,维护一个X一个Y。对于每个项,如果我们读到了字符d,那么他就是骰子类型,我们之前读到的数就应该是X,后面的数就应该是Y,否则我们读到的就只是X。

除此之外,还需要记住最后一次读到的项也需要参与运算。我们可以在字符串后面接一个加号,这样就可以不需要特殊处理最后一项了。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N=1010;

string str;

LL eps;
LL up,down;
LL cnt[N];    //代表i面色子要用多少个 

int main()
{
    cin>>str;
    
    str="+"+str+"+";
    
    LL num=0,S=0;    
    bool flag=false;    //代表这个是不是色子 
    bool op=true;        //true代表加 false代表减 
    for (int i=0;i<str.size();i++)
    {
        auto t=str[i];
        if (t=='+' || t=='-')
        {
            if (!flag)    
            {
                if (op)    eps+=S;
                else eps-=S;
                S=0;
            }
            else
            {
                cnt[S]+=num;
                
                if (op)    
                {
                    up+=num*S;
                    down+=num;
                }
                else
                {
                    up-=num;
                    down-=num*S;
                }
                
            }
            S=0;num=0;        
            flag=false;    
            
            if (t=='+')    op=true;
            else op=false;
        }
        else if (t=='d')
        {
            if (str[i-1]=='+' || str[i-1]=='-')
                S=1;
            
            num=S;
            S=0;
            flag=true;
        }
        else
        {
            S=S*10+t-'0';
        }
    }
    
    for (int i=1;i<N;i++)
        if (cnt[i])
            cout<<i<<" "<<cnt[i]<<endl;
    
    cout<<down+eps<<" "<<up+eps;

    return 0;
}

第四题

    cout<<"GG";

这到底是什么玩意啊喂!出题组真有你的啊。

第五题

第五题还是蛮有意思的,虽然我读题读了半天才看懂。

题目大意是给定一棵树,然后问你选两个点,这两个点之间没有边相连 且 只选这两个点,然后连上边之后可以形成一个二分图,问你有多少种选法。

这个题一开始真给我看蒙了,原因很简单:这树不是本来就是二分图吗???读了半天题又模拟了一遍样例之后我才看懂,是让你选两个点连线之后仍然是二分图。

首先我们要明白什么是二分图。通俗点来说,如果在一个图里任选一个点,这个点染成黑色,然后将与这个点相连的所有点染成白色,再将与这些白色点相邻的所有点染成黑色,如此反复到最后,任意两个有边相邻的点的颜色都不同,这就是一个二分图(这不就是染色法判定二分图嘛)。

那么,我们也不难验证出,树因为不存在回路,那么本身就是一个二分图。如何选两个点后还能保证是二分图呢?我们可以先对树用染色法染色,然后在对于一个点,去找那些和他颜色不同的点连边,就不会破坏二分图的性质。

假如,我们设置根的节点为黑色,深度为1,那么我们不难想象出,由于树是一层一层的,所以深度为奇数的就都是黑色,所有深度为偶数的就都是白色。那么暴力做法很容易想象到,我们n^2枚举所有点,判断是否有边相连,且是否颜色不同即可。

代码已经删了 我只记得这个做法能拿19分。

既然已经想到了暴力做法,那么其实离能AC的写法已经差不远了。我们想一下,所有点其实只会和深度比自己大的异色点相连,而异色也就代表深度的奇偶性不同,同时有些边已经存在了不能重复连,这些边的数量就是当前层所有点的出度之和。

那么,我们先bfs出每一层的出度和每一层有多少个点,然后我们动态地维护深度更深的层有多少个点,每次算完当前层之后就将奇/偶层的点数和减去当前层的即可。

#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> PII; 
typedef long long LL;
const int N=1000010;

int n;
int depth[N],root,deepest;
int h[N],e[2*N],ne[2*N],idx;
int cnt[N];
int deg[N],Size[N],Sdeg[N];
//deg[i]为第i个点的出度 Size[i]为第i层有多少个点 Sdeg[i]为第i层点的出度之和
void bfs()
{
    memset(depth,0x3f,sizeof(depth));
    depth[root]=1;
    
    queue<int> q;q.push(root);
    while(q.size())
    {
        int t=q.front();q.pop();
                
        Size[depth[t]]++;
        for (int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if (depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                deg[t]++;
                deepest=max(deepest,depth[j]);
                q.push(j);
            }
        }
        Sdeg[depth[t]]+=deg[t];
    }
}

void add(int a,int b)
{
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}

int main()
{
    cin>>n;
    
    memset(h,-1,sizeof(h));
    for (int i=1;i<=n-1;i++)
    {
        int a,b;cin>>a>>b;
        if (a>b)    swap(a,b);
        add(a,b);add(b,a);
        cnt[a]++;cnt[b]++;
    }
    
    root=-1;
    for (int i=1;i<=n;i++)
        if (cnt[i]==1)
        {
            root=i;break;    
        } 
        
    bfs();
    
    LL sumji=0,sumou=0;
    for (int i=1;i<=deepest;i++)
        if (i%2==1)    
            sumji+=Size[i];
        else 
            sumou+=Size[i];
            
    LL ans=0;
    for (int i=1;i<=deepest;i++)
        if (i%2==1)
        {
            ans=ans+Size[i]*sumou-Sdeg[i];
            sumji-=Size[i];
        }
        else
        {
            ans=ans+Size[i]*sumji-Sdeg[i];
            sumou-=Size[i];
        }        
    
    cout<<ans;    
    return 0;
}

最后摸了76分TAT没有AK我好菜。


本文转载自: https://blog.csdn.net/Rinnoluo/article/details/125712242
版权归原作者 林梦落 所有, 如有侵权,请联系我们删除。

“2022 Robocom世界机器人开发者大赛 CAIP编程赛道 本科组-省赛 挨打记录+题解”的评论:

还没有评论