Loading

AtCoder Beginner Contest 258 A - F

传送门

这场打的有一种我又行了的感觉

A - When?

向下取整 + 取余

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;

int main()
{
    int x;
    scanf("%d", &x);
    printf("%02d:%02d\n", 21 + x / 60, x % 60);

    return 0;
}

B - Number Box

暴力枚举

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
string s[20];
int n;
const int xi[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int yi[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

ll solve(int x, int y, int k)
{
    ll ans = s[x][y] - '0';
    for(int i=1; i<n; i++)
    {
        x += xi[k];
        y += yi[k];
        x = (x + n) % n;
        y = (y + n) % n;
        ans = ans * 10 + s[x][y] - '0';
    }
    return ans;
}

int main()
{
    cin >> n;
    for(int i=0; i<n; i++) cin >> s[i];
    ll ans = 0;
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            for(int k=0; k<8; k++)
            {
                ans = max(solve(i, j, k), ans);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

C - Rotation

将其看做一个循环的字符串,操作一就是当前指针向后移 x 个位置

操作二就是当前指针的后 x 个位置是啥

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, q;
    cin >> n >> q;
    string s;
    cin >> s;
    int tp = 0;
    while(q--)
    {
        int a, b;
        cin >> a >> b;
        if(a == 1) tp = (tp - b + n) % n;
        else
            cout << s[(tp + b - 1 + n) % n] << '\n';
    }
    return 0;
}

D - Trophy

贪心

打游戏的时候都知道,解锁前置关卡,直到打到收益最高的关卡就一直刷副本

因此答案肯定是解锁完前置关卡就不断刷,找到最小值就行

巨大坑:初始值一定要很大很大(不会有人因此 wa 了 3 发吧)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef unsigned long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 4e18 + 10;
ll a[maxn], b[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ll n, m;
    cin >> n >> m;
    for(int i=0; i<n; i++)
        cin >> a[i] >> b[i];
    ll ans = inf, temp = 0;
    for(int i=0; i<n && m; i++)
    {
        m--;
        temp += a[i] + b[i];
        ans = min(ans, temp + b[i] * m);
    }
    cout << ans << endl;
    return 0;
}

E - Packing Potatoes

二分 + 循环

无限多的物品,模拟是不现实的,考虑从 \(n\) 种物品下手

在第 \(i\) 种物品中,我们可以计算,装满盒子之后需要连续放多少个物品,而且还能知道装完之后是在哪种物品停下来

因此我们考虑建立一条有向边,\(i -> j\) 代表如果当前盒子第一个放入的是第 \(i\) 种物品,则下一个盒子的第一个放入的物品是第 \(j\) 种物品

这样每种物品都会发出一条有向边,总共是 \(n\) 条有向边

不难发现,从第一个物品开始往后跳转,如果这样一直跳转下去的话,会存在一个循环

我们只要对询问的答案,判断一下是否能进入循环,如果不进入,就直接返回答案;如果进入,就取模判断一下最后在循环的哪一步停下来

这样一个无穷大的问题就变成一个循环取模的问题

建立有向边的时候考虑用 前缀和 + 二分 的方式来求,剩下的都是亿点细节问题

细节:

  • 二分的时候,可能会存在 \(n\) 种物品全部取出来都不够装一个盒子的,因此要提前将 \(x\)\(sum\) 取模

  • 求取答案未进入到循环之前,不能进入有向边一个一个找,要提前预处理好进入循环前,第 \(i\) 个盒子是哪一步,不然会 TLE

  • 如果是从 \(1\) 开始的,注意好下标,特别是取模的时候

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e16 + 10;
ll num[maxn], sum[maxn], nex_num[maxn];
int nex[maxn], vis[maxn];
int alp[maxn];

int main()
{
    int n, q, x;
    cin >> n >> q >> x;
    for(int i=1; i<=n; i++)
    {
        cin >> num[i];
        sum[i] = sum[i-1] + num[i];
    }
    ll rx = x / sum[n];
    x %= sum[n];
    for(int i=1; i<=n; i++)
    {
        int way = 0;
        nex_num[i] = rx * n;
        if(sum[n] - sum[i-1] >= x)
        {
            way = lower_bound(sum + 1, sum + 1 + n, x + sum[i-1]) - sum;
            nex_num[i] += way - i + 1;
        }
        else
        {
            way = lower_bound(sum + 1, sum + 1 + n, x - sum[n] + sum[i-1]) - sum;
            nex_num[i] += n - i + 1 + way;
        }
        nex[i] = way + 1;
        if(nex[i] > n) nex[i] = 1;
    }
    int now = 1, dep = 1;
    while(vis[now] == 0)
    {
        vis[now] = dep;
        alp[dep] = now;
        dep++;
        now = nex[now];
    }
    ll pre = vis[now] - 1, rnd = dep - vis[now];
    while(q--)
    {
        ll k;
        cin >> k;
        ll ans = 0;
        if(k <= pre)
            ans = nex_num[alp[k]];
        else
        {
            k -= pre + 1;
            k %= rnd;
            ans = nex_num[alp[k + pre + 1]];
        }
        cout << ans << endl;
    }
    return 0;
}

F - Main Street

基本的思路就是,点到点的最短路径只能是两种方式:

  • 直接走,不走通道

  • 走通道

走通道的做法就考虑必经点,即起点对 4 个方向各发出一条射线,与会最近的通道分别产生 \(4\) 个交点,走通道的最短路必然会经过这四个点的其中一个

同理,终点也能产生四个必经点

走通道的最短路,必然是在这两组点的最短路之间产生,总共 \(16\) 种方式

答案就取最小值就好了

以上均为我的想法,代码实现还没写,有些细节还要处理下

(不鸽,会补题的!)

更新:

感觉细节真的很多,参考了一下 jiangly 和 tourist 的代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <array>
#include <vector>
using namespace std;
typedef long long ll;
#define pii pair<ll, ll>
ll B, K, sx, sy, ex, ey;

pii query(ll x, ll y, int way)
{
    if(way == 0) x -= x % B;
    else if(way == 1) x += B - x % B;
    else if(way == 2) y -= y % B;
    else y += B - y % B;
    return {x, y};
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--)
    {
        cin >> B >> K >> sx >> sy >> ex >> ey;
        ll ans = (abs(sx - ex) + abs(sy - ey)) * K;
        for(int i=0; i<4; i++)
        {
            for(int j=0; j<4; j++)
            {
                auto [qx, qy] = query(sx, sy, i);
                auto [px, py] = query(ex, ey, j);
                ll cnt = (abs(sx - qx) + abs(sy - qy) + abs(ex - px) + abs(ey - py)) * K;
                if(qx % B == 0 && px % B == 0 && qy / B == py / B)
                {
                    ll r = qy % B + py % B;
                    if(qx != px)
                        cnt += abs(qx - px) + min(r, 2 * B - r);
                    else
                        cnt += abs(qy - py);
                }
                else if(qy % B == 0 && py % B == 0 && qx / B == px / B)
                {
                    ll r = qx % B + px % B;
                    if(qy != py)
                        cnt += abs(qy - py) + min(r, 2 * B - r);
                    else
                        cnt += abs(qx - px);
                }
                else
                    cnt += abs(qx - px) + abs(qy - py);
                ans = min(ans, cnt);
            }
        }
        cout << ans << '\n';
    }
    return 0;
}
posted @ 2022-07-04 15:02  dgsvygd  阅读(49)  评论(0编辑  收藏  举报