[补题报告] ABC358 (目前更新ABCDG)

Link:ABC58

A

Description

给定两个字符串,判定两个字符串是否分别为 AtCoder ,Land 。大小写敏感。

Analysis

模拟即可。

Code

A
#include <bits/stdc++.h>
using namespace std;
string a,b;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>a>>b;
    if(a == "AtCoder" && b == "Land") cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

B

Description

每人的购票过程需要 \(A\) 秒。一旦排在队伍前面的人完成购票,下一个人(如果有的话)就会立即开始他们的购票过程。

目前,没有人排队, \(N\) 人会陆续前来购票。具体来说, 第 \(i\) 人将在 \(T_i\) 秒后到达售票点。如果已经有人排队,他们会排在队伍的最后;如果没有,他们会立即开始购票。这里

对于 \(\forall i(1 \leq i \leq N)\) ,求从 \(0\) 时刻起每个人完成购票时间。

Analysis

模拟题。

定义 \(t\) 为当前时间,初始化 \(t=0\),然后判断当前人是否需要排队,如果不需则当前时刻为 当前人的到达时间 \(+\) 购票时间 \(A\),如果需要排队则当前时间为 当前时间 \(+\) 购票时间。然后对于每个人,输出当前时间即可。

Code

B
#include <bits/stdc++.h>
using namespace std;
int a,n;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>a;
    int nowt = 0;
    for(int i=1;i<=n;i++)
    {
        int t;
        cin>>t;
        if(t >= nowt) 
        {
            nowt = t + a;
        }
        else nowt += a;
        cout<<nowt<<endl;
    }
    return 0;
}

C

Description

共有 \(n\) 个店铺,\(m\) 中商品,每个店铺提供的商品由一个长度为 \(m\) 的字符串表示。定义第 \(i\) 个店铺的字符串为 \(S_i\),若 \(S_{i,j}(i\le n,j\le m)='o'\) 表示第 \(j\) 中商品本店提供。反之若 \(S_{i,j}(i\le n,j\le m)='x'\) 表示第 \(j\) 中商品本店不提供。

你需要求至少需要拜访几个商店才能买到所有的商品。

\(n \ge 1,m\le 10\)

Analysis

注意到数据范围太小,直接 dfs 即可。

dfs 函数内记录当前拜访商店数量,当前商店坐标,以及当前拥有的商品状态。

这里可以拿 bitset 用,直接按位或运算即可。

Code

C
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int INF = 0x3f3f3f3f;
string s[N];
int n,m;
int minn = INF;
void dfs(int t,bitset <N> b,int num)
{
    if(b.count() == m)
    {
        minn = min(minn,num);
        return;
    }
    if(t > n) return;
    bitset <N> tt = b;
    bitset <N> l;
    for(int i=0;i<s[t].size();i++) 
    {
        if(s[t][i] == 'o') 
        {
            l[i] = 1;
         //   cout<<l[i]<<endl;
        }
        else l[i] = 0;
    }
    //cout<<l<<endl;
    tt |= l;
    dfs(t+1,b,num);
    dfs(t+1,tt,num+1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
    }
    bitset <N> b;
    dfs(1,b,0);
    cout<<minn<<endl;
    return 0;
}

D

Description

AtCoder 乐园的一家纪念品商店出售 \(N\) 盒子。
这些盒子的编号为 \(1\)\(N\) ,盒子 \(i\) 的价格为 \(A_i\) 日元,里面有 \(A_i\) 块糖果。
高桥想从 \(N\) 盒中买下 \(M\) 盒,然后给 \(M\) 个叫 \(1, 2, \ldots, M\) 的人每人一盒。
在这里,他想买的盒子要满足以下条件:

  • 对于每个 \(i = 1, 2, \ldots, M\) 人, \(i\) 都能得到至少装有 \(B_i\) 粒糖果的盒子。
    请注意,不允许给一个人多个盒子,也不允许给多个人同一个盒子。
    求是否可能买到满足条件的 \(M\) 盒,如果可能,求高桥需要支付的最小总金额。

Analysis

第一眼发现可以二分,对于 \(\forall B_i\),二分在 \(A\) 中找出大于等于 \(B_i\) 的最小值,然后删掉。这样的贪心是正确的。如果不这么做不会使答案更优。

但是,上述做法中需要实现删除操作,删除操作复杂度使 \(O(n)\) 的,无法接受。会 T 飞。

注意到上述贪心符合单调性,考虑双指针。

不妨将 \(A,B\) 序列排序,然后依据上述贪心法双指针扫一下即可。对于 \(\forall B_i\),找到 \(A_i \geq B_i\) 然后指针移动。如果未找到则不合法。

Code

D
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int a[N],b[N];
int n,m;
int ans = 0;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=m;i++) 
        cin>>b[i];
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    int i= 1,j = 1;
    for(;j<=m;j++,i++)
    {
        bool flg = 0;
        for(;i<=n;i++)
        {
            if(a[i] >= b[j])
            {
              //  i++;
                flg = 1;
                ans += a[i];
                break;
            }
        }
        if(!flg)
        {
            cout<<"-1"<<endl;
            return 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}

G

Description

AtCoder Land 由一个网格表示,网格中有 \(H\) 行和 \(W\) 列。让 \((i, j)\) 表示第 \(i\) 行和第 \(j\) 列的单元格。

高桥从 \((sx,sy)\) 单元格开始,重复以下操作 \(K\) 次:

  • 他要么停留在当前单元格,要么移动到相邻单元格。在这个操作之后,如果他在 \((i, j)\) 单元格中,他将获得 \(A_{i, j}\) 的趣味值。

请找出他能获得的最大总乐趣值。

这里,当且仅当 \(|x - x'| + |y - y'| = 1\) 时, \((x', y')\) 单元格被视为与 \((x, y)\) 单元格相邻。即他只可以四方向移动。

Analysis

如果去掉可以停留,那这个题和方格取数差不多,就是一个裸的 dp。

结论:最优方案一定是走到一个点然后停下来。

为什么呢?想一下,如果我们用 dp 确定了一条路径是最优解,那么走到这条路径上的最大值,然后停下来的策略一定不会比继续走更劣。

显然不存在先在其他点停几步在走情况,因为在其他点停留的步数不如给最大值。

所以,最优解的形式一定是走到一个点然后停下来。

显然本题是一个 dp 题。考虑设计状态,因为有决策数量限制,故决策数量也应当是一个状态。令 \(f_{t,i,j}\) 表示已经进行了 \(t\) 个决策,走到 \((i,j)\) 时的最大值。这里的最大值显然不包括在这个点停留的,因为这玩意没法转移。

状态转移方程显然, \(f_{t,i,j}=\max(f_{t,i,j},f_{t-1,i+dx_i,j+dy_i})\)\(dx_i,dy_i\)) 分别表示四方向移动。

然后考虑细节。

首先考虑转移顺序,观察方程发现每次取 max 依赖于上一步的状态。也就是说,这一步计算时上一步的所有状态必须都已经计算完。所以,第一层循环需要枚举状态。

然后考虑初始化,每次是取 \(\max\),故初始令 \(f\) 全度为 负无穷大。且 \(f_{0,sx,sy}=0\)。因为我们计算是从第一次决策开始的。

每一个决策数量计算完后,可以更新一下 \(ans\)。一定注意停留的答案不能转移。

Code

Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3050;
const int INF = 0x3f3f3f3f;
int sx,sy;
int n,m,k;
int mapp[N][N];
int f[N][60][60];
int ans;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m>>k;
    cin>>sx>>sy;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>mapp[i][j];
          //  for(int p=1;p<=n*m;p++) f[p][i][j] = 128;
        }
    }
    ans = k*mapp[sx][sy];
    memset(f,128,sizeof(f));
    f[0][sx][sy] = 0;
    for(int t=1;t<=min(n*m,k);t++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int kk=0;kk<4;kk++)
                {
                    int ax = i+dx[kk],ay = j + dy[kk];
                    if(!(ax>=1 && ax <= n && ay >= 1 && ay <= m)) continue;
                    f[t][i][j] = max(f[t][i][j],f[t-1][ax][ay]+mapp[i][j]);
                }
                //f[t][i][j] += mapp[i][j];
                ans = max(ans,f[t][i][j]+(k-t)*mapp[i][j]);
            }
        }
         for (int x = 1; x <= n; x++)
            for (int y = 1; y <= m; y++) ans = max(ans,f[t][x][y] + (k-t)*mapp[x][y]);
    }
    cout<<ans<<endl;
    return 0;
}
posted @   SXqwq  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示