Title

Atcoder Beginner Contest 395记录

AtCoder Beginner Contest 395记录

A - Strictly Increasing?

模拟

思路

直接遍历一遍就行

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;
int nums[110];
void solve()
{
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= n; i++) std::cin >> nums[i];
    for (int i = 1; i < n; i++)
    {
        if (nums[i] >= nums[i + 1])
        {
            std::cout << "No" << endl;
            return;
        }
    }
    std::cout << "Yes" << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}


B - Make Target

模拟

思路

找到规律直接模拟

要涂色的图形是左上和右下坐标分别为(i,i)(n+1i,n+1i)的正方形边框,而且i是奇数,一层一层染色就好

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long

char mat[55][55];
void solve()
{
    memset(mat, '.', sizeof(mat));
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= (n + 1) / 2; i += 2)
    {
        for (int j = i; j <= n + 1 - i; j++)
        {
            mat[i][j] = '#';
            mat[j][i] = '#';
            mat[n + 1 - i][j] = '#';
            mat[j][n + 1 - i] = '#';
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            std::cout << mat[i][j];
        }
        std::cout << endl;
    }
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}


C - Shortest Duplicate Subarray

思维

思路

可以记录每一个数上次出现的位置,这个数再次出现时就更新答案

也可以使用滑动窗口,这里用的滑动窗口,有些麻烦了

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long

int nums[200010];
std::deque<int> q;
int cnt[1000010];
void solve()
{
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= n; i++)
    {
        std::cin >> nums[i];
    }
    int ans = 1e12;
    for (int i = 1; i <= n; i++)
    {
        if(q.empty())
        {
            cnt[nums[i]]++;
            q.push_back(nums[i]);
            continue;
        }
        q.push_back(nums[i]);
        cnt[nums[i]]++;
        if (cnt[nums[i]] == 2)
        {
            while(cnt[nums[i]] == 2)
            {
                int t = q.front();
                q.pop_front();
                cnt[t]--;
            }
            ans = std::min(ans, (int)q.size() + 1);
        }
    }
    if (ans == 1e12)
    {
        std::cout << -1 << endl;
    }
    else
    {
        std::cout << ans << endl;
    }
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}


D - Pigeon Swap

思维

思路

不要看错问题,操作2是把ab鸽巢交换位置,不是把其中一个的鸽子移动到另外一个

鸽巢的位置是变化的,但是交换鸽巢的时候鸽子的位置不变化,可以维护鸽子在哪个位置,鸽巢在哪个位置,每个位置上放的是哪一个鸽巢

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 1e6 + 5;
const int inf = 0x7f7f7f7f;
int faz[maxn]; // faz[i]鸽子i在哪一个位置
int pos[maxn]; // pos[i]笼子i在哪一个位置
int mp[maxn];  // mp[i]位置i是哪一个笼子
void solve()
{
    int n = 0, q = 0;
    std::cin >> n >> q;
    for (int i = 1; i <= n; i++)
    {
        faz[i] = i;
        pos[i] = i;
        mp[i] = i;
    }
    int k = 0, a = 0, b = 0;
    for (int i = 1; i <= q; i++)
    {
        std::cin >> k;
        if(k == 1)
        {
            std::cin >> a >> b;
            faz[a] = pos[b];
        }
        else if (k == 2)
        {
            std::cin >> a >> b;
            int t1 = pos[a], t2 = pos[b];
            pos[a] = t2;
            pos[b] = t1;
            mp[t1] = b;
            mp[t2] = a;
        }
        else
        {
            std::cin >> a;
            std::cout << mp[faz[a]] << endl;
        }
    }
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}


E - Flip Edge

最短路,动态规划,思维

思路

有点类似于分层图?

多了一种可以反转边的操作,那么在使用Dijkstra的时候就多了一种状态

dp[i][0/1]:到达顶点i时此时全局是反转前/后的状态的最小花费

因为有反转状态,所以存图的时候反边也要存下来,但是要记录状态,这里为了方便可以用链式前向星存图

struct Edge
{
    int u, v, st, nxt;
}edge[maxn << 1];

st为0时说明这条边是反转之前的边,st为1时说明这条边是反转之后的边

状态转移:

当走边(u,v)时,若st=0, 对dp[v][0]操作, dp[v][0]可由dp[u][1]dp[u][0]转移,前者需要反转而后者不需要,st=1是类似

if (edge[i].st == 0)
{
    if(dp[tt][0] > dp[t][0] + 1)
    {
        dp[tt][0] = dp[t][0] + 1;
        q.push({tt, dp[tt][0], 0});
    }
    if (dp[tt][0] > dp[t][1] + x + 1)
    {
        dp[tt][0] = dp[t][1] + x + 1;
        q.push({tt, dp[tt][0], 0});
    }
}
else
{
    if (dp[tt][1] > dp[t][1] + 1)
    {
        dp[tt][1] = dp[t][1] + 1;
        q.push({tt, dp[tt][1], 1});
    }
    if (dp[tt][1] > dp[t][0] + x + 1)
    {
        dp[tt][1] = dp[t][0] + x + 1;
        q.push({tt, dp[tt][1], 1});
    }
}

update:额,就是分层图,写法复杂了,有时间在补一下

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;

int cnt = 0;
int head[maxn];
int vis[maxn][2];
int dp[maxn][2]; // dp[i][1/0] 到达顶点i当前状态是/否反转的最小花费
struct Edge
{
    int u, v, st, nxt;
}edge[maxn << 1];


struct Node
{
    int to, w, st;
    bool operator < (const Node &t) const
    {
        return w > t.w;
    }
};
std::priority_queue<Node> q;
void AddEdge(int u, int v, int st)
{
    edge[++cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].st = st;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}
int n = 0, m = 0, x = 0;
void dij()
{
    q.push({1, 0, 0});
    dp[1][0] = 0;
    while(!q.empty())
    {
        Node tmp = q.top();
        q.pop();
        if (vis[tmp.to][tmp.st]) continue;
        vis[tmp.to][tmp.st] = 1;
        int t = tmp.to;
        for (int i = head[t]; i != -1; i = edge[i].nxt)
        {
            int tt = edge[i].v;
            if (edge[i].st == 0)
            {
                if(dp[tt][0] > dp[t][0] + 1)
                {
                    dp[tt][0] = dp[t][0] + 1;
                    q.push({tt, dp[tt][0], 0});
                }
                if (dp[tt][0] > dp[t][1] + x + 1)
                {
                    dp[tt][0] = dp[t][1] + x + 1;
                    q.push({tt, dp[tt][0], 0});
                }
            }
            else
            {
                if (dp[tt][1] > dp[t][1] + 1)
                {
                    dp[tt][1] = dp[t][1] + 1;
                    q.push({tt, dp[tt][1], 1});
                }
                if (dp[tt][1] > dp[t][0] + x + 1)
                {
                    dp[tt][1] = dp[t][0] + x + 1;
                    q.push({tt, dp[tt][1], 1});
                }
            }
        }
    }
}

void solve()
{
    std::cin >> n >> m >> x;
    for (int i = 1; i <= n; i++)
    {
        head[i] = -1;
        dp[i][0] = dp[i][1] = 1e18;
    }
    int u, v;
    for (int i = 1; i <= m; i++)
    {
        std::cin >> u >> v;
        AddEdge(u, v, 0);
        AddEdge(v, u, 1);
    }
    dij();
    std::cout << std::min(dp[n][0], dp[n][1]);
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}


F - Smooth Occlusion

思路

花费最多的情况就是H=0,把所有的变成0,假设总花费为s

如果找到一个合法的H,总花费就成了sHn, H在合法范围内越大越好二分答案

那么如何check

H一定时,花费确定,不用想怎么使得花费最小,我们可以找出一个u[i]的取值区间判断这个区间合不合法

对于第一个牙齿区间就是[max(0,hd[1]),min(u[i],h)]

对于第i(2i)个牙齿首先要在区间[tleft=max(0,hd[i]),  tright=min(u[i]),h]中,其次最小值还可以要拓展到上一个(区间的最小值)- x, 最大值要拓展到上一个(区间最大值) + x

然后判断区间合不合法就好了:区间左端点<=区间右端点

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;

struct custom_hash 
{
	static uint64_t splitmix64(uint64_t x) 
    {
		x ^= x << 13;
		x ^= x >> 7;
		x ^= x << 17;
		return x; 
	}
	size_t operator () (uint64_t x) const 
    {
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
		return splitmix64(x + FIXED_RANDOM);
	}
};

int u[maxn], d[maxn];
 int n = 0, x = 0;
bool check(int h)
{
    int mn = std::max(h - d[1], 0ll);
    int mx = std::min(u[1], h);
    if (mx < mn) return false;
    for (int i = 2; i <= n; i++)
    {
        int tle = std::max(h - d[i], 0ll);
        int tri = std::min(u[i], h);
        int tmn = std::max(tle, mn - x);
        int tmx = std::min(tri, mx + x);
        if (tmx < tmn) return false;
        mn = tmn, mx = tmx;
    }
    return true;
}

void solve()
{
    std::cin >> n >> x;
    int s = 1e18, sum = 0;
    for (int i = 1; i <= n; i++)
    {
        std::cin >> u[i] >> d[i];
        s = std::min(s, u[i] + d[i]);
        sum += u[i] + d[i];
    }
    int l = -1, r = s + 1;
    while(l + 1 < r)
    {
        int h = (l + r) >> 1;
        if(check(h))
        {
            l = h;
        }
        else
        {
            r = h;
        }
    }
    std::cout << sum - l * n << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

posted @   栗悟饭与龟功気波  阅读(14)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示