AtCoder Beginner Contest 337

ABC337总结

A - Scoreboard

翻译

Takahashi 队和 Aoki 队进行了\(N\)场比赛。在\(i\)/th比赛\((1\leq i\leq N)\)中,Takahashi 队得了\(X _ i\)分,Aoki 队得了\(Y _ i\)分。在\(N\)场比赛中总得分较高的队伍获胜。

输出获胜者。如果两队总得分相同,则输出 Draw

分析

将得分分别加起来进行比较即可。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;

int n,m,t,a[N];

int main ()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        m+=x,t+=y;
    }
    if(m>t) cout<<"Takahashi";
    else if(m==t) cout<<"Draw";
    else cout<<"Aoki";
    return 0;
}

B - Extended ABC

翻译

我们将扩展 A 字符串、扩展 B 字符串、扩展 C 字符串和扩展 ABC 字符串定义如下:

  • 如果 \(S\) 中的所有字符都是 A,则字符串 \(S\) 是扩展 A 字符串。
  • 如果 \(S\) 中的所有字符都是 B,则字符串 \(S\) 是扩展 B 字符串。
  • 如果 \(S\) 中的所有字符都是 C,则字符串 \(S\) 是扩展 C 字符串。
  • 如果存在扩展 A 字符串 \(S_A\)、扩展 B 字符串 \(S_B\) 和扩展 C 字符串 \(S_C\),且按此顺序连接 \(S_A, S_B, S_C\) 得到的字符串等于 \(S\),则字符串 \(S\) 是扩展 ABC 字符串。

例如,ABCAAAABBBCCCCCCC是扩展 ABC 字符串,但ABBAAACBBBCCCCCCCAAA不是。请注意,空字符串是扩展 A 字符串、扩展 B 字符串和扩展 C 字符串。

给您一个由 ABC 组成的字符串 \(S\)。如果 \(S\) 是扩展 ABC 字符串,则输出 Yes;否则输出 No

分析

设当前位置为 \(i\),按照题意,\(i+1\)\(i\) 的字母的值大 \(1\)\(0\),且只存在 A B C

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;

int n,m,t,a[N];

int main ()
{
    string s;
    cin>>s;
    int st=1;
    for(char c:s)
    {
        if(c=='A'+t) continue;
        if(c>'A'+t) t++;
        if(c<'A'+t||t>2)
        {
            st=0;
            break;
        } 
    }
    if(st) cout<<"Yes";
    else cout<<"No";
    return 0;
}

C - Lining Up 2

翻译

\(N\)人在排队:\(1\)人、\(2\)人、\(\ldots\)人、\(N\)人。

给你的是长度为\(N\)的序列\(A=(A _ 1,A _ 2,\ldots,A _ N)\)

\(A _ i\ (1\leq i\leq N)\) 表示以下信息:

  • 如果是\(A _ i=-1\),则\(i\)排在队伍的最前面;
  • 如果是\(A _ i\neq -1\),则\(i\)紧跟在\(A _ i\)后面。

从前面到后面输出一行人的编号。

分析

相当于告诉你每个人的前面是谁,直接用链表模拟即可。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;

int n,m,t,a[N],ne[N];

int main ()
{
    cin>>n;
    memset(ne,-1,sizeof(ne));
    for(int i=1;i<=n;i++) 
    {
        cin>>m;
        if(m==-1) m=0;
        ne[i]=ne[m];
        ne[m]=i;
    }
    for(int i=ne[0];i;i=ne[i]) cout<<i<<" ";
    return 0;
}

D - Cheating Gomoku Narabe

有一个网格,网格中有 \(H\) 行和 \(W\) 列。让 \((i, j)\) 表示从上往下第 \(i\) 行和从左往右第 \(j\) 列的单元格。

每个单元格包含一个字符 ox.。写在每个单元格中的字符由长度为\(W\)\(H\)字符串\(S_1, S_2, \ldots, S_H\)表示;写在单元格\((i, j)\)中的字符是字符串\(S_i\)中的\(j\)个字符。

对于此网格,您可以重复以下操作任意多次,可能为零:

  • 选择一个带有字符 . 的单元格,并将该单元格中的字符更改为 o

确定是否有可能在所有单元格中都写上 o\(K\)个水平或垂直连续的单元格序列(换句话说,至少满足以下两个条件中的至少一个)。如果可能,请输出实现这一目标所需的最少操作数。

  • 有一对整数\((i, j)\)满足\(1 \leq i \leq H\)\(1 \leq j \leq W-K+1\),使得单元格\((i, j), (i, j+1), \ldots, (i, j+K-1)\)中的字符都是 o
  • 有一个满足 \(1 \leq i \leq H-K+1\)\(1 \leq j \leq W\) 的整数对 \((i, j)\) ,使得单元格 \((i, j), (i+1, j), \ldots, (i+K-1, j)\) 中的字符都是 o

分析

一开始想复杂了,其实暴力求就可以。每行每列分开看,用 \(cnt1\) 记录 o 的数量,用 \(cnt2\) 记录.o 的数量,当 \(cnt2 \ge k\) 时,就计算答案。用类似滑动窗口,单调队列的思想,当 \(cnt2 > k\) 时,最开始的那个就对答案不产生影响,直接去掉,就是 cnt1--。最后 \(ans=k-cnt1\),找出最小值。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,k,ans=N;
string s[N];
int main ()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) cin>>s[i],s[i]="0"+s[i];
    for(int i=1;i<=n;i++)
    {
        int cnt1=0,cnt2=0;
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='x') cnt1=cnt2=0;
            else if(s[i][j]=='o') cnt1++,cnt2++;
            else cnt2++;
            if(cnt2>k&&s[i][j-k]=='o') cnt1--;
            if(cnt2>=k) ans=min(ans,k-cnt1);
        }
    }
    for(int j=1;j<=m;j++)
    {
        int cnt1=0,cnt2=0;
        for(int i=1;i<=n;i++)
        {
            if(s[i][j]=='x') cnt1=cnt2=0;
            else if(s[i][j]=='o') cnt1++,cnt2++;
            else cnt2++;
            if(cnt2>k&&s[i-k][j]=='o') cnt1--;
            if(cnt2>=k) ans=min(ans,k-cnt1);
        }
    }
    if(ans==N) cout<<-1;
    else cout<<ans;
    return 0;
}

E - Bad Juice

翻译

\(n\) 杯果汁,其中一杯是发霉的,喝了发霉的果汁会窜稀。

现在你不知道哪杯是发霉的,但明天你要把这些果汁因此你想去坑你的好基友,让他们喝下这些果汁。每个基友可以喝很多杯果汁,每杯果汁可以被很多基友喝。

为了得罪尽量少的人,请求出最少需要给多少基友喝果汁,并构造出一种方案。

接下来用一个字符串 \(s\) 给出你的方案中每个人的窜稀情况,1 代表窜稀,0 代表没有窜稀。你需要据此输出发霉的果汁编号。

交互题。先读入 \(n\),然后输出方案,然后读入 \(s\),然后输出发霉的果汁编号。每次输出完需要刷新标准输出。编号全部从 \(1\) 开始。

交互方式示例:

请在输出完毕后使用 fflush(stdout)endl 清空缓冲区,然后再获得下一个输入。

输入 输出 解释
3 给出 \(n\)
2 输出叫的朋友人数。
2 1 2 给第一个朋友喝果汁 \(1\) 和果汁 \(2\)
1 2 给第二个朋友喝果汁 \(2\)
10 给出每个朋友是否肚子疼。
1 输出发霉的果汁编号。

分析

第一次做交互题,有点新奇但不多,就只需要读入输出再读入再输出就好了。本题方法略微有些新奇(幸好我见过 qwq),要运用二进制的方法,对于第 \(i\) 号朋友,需要给他喝所有编号二进制下从小到大第 \(i\) 位为 \(1\) 的果汁,这样如果他出事了,那么坏了的果汁在二进制下的第 \(i\) 位一定为 \(1\)(不为 \(1\) 就喝不到,也就不会出事)。那么 \(m=\log_2{n-1}+1\), 为何减一?如果 \(n\) 等于 \(2\) 的多少次方,那我就要让最后一位朋友和这第 \(n\) 号果汁,可我完全可以把第 \(n\) 号果汁留下,所有人都无事就能说明坏掉的果汁是第 \(n\) 号。

要注意交互题的一些注意事项。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;

int n,m,t,log_2[N];
string s;
int main ()
{
    cin>>n;
    for(int i=2;i<=n;i++) log_2[i]=log_2[i>>1]+1;
    m=log_2[n-1]+1;
    cout<<m<<"\n";
    for(int i=0;i<m;i++)
    {
        int cnt=0;
        for(int j=1;j<=n;j++) if((1<<i)&j) cnt++;
        cout<<cnt<<" ";
        for(int j=1;j<=n;j++) if((1<<i)&j) cout<<j<<" ";
        cout<<"\n";
    }
    cin>>s;
    int ans=0;
    for(int i=0;i<s.size();i++) if(s[i]=='1') ans+=1<<i;
    if(ans==0) ans=n;
    cout<<ans;
    return 0;
}

posted @ 2024-01-30 15:28  zhouruoheng  阅读(93)  评论(1编辑  收藏  举报