KAJIMA CORPORATION CONTEST 2024(AtCoder Beginner Contest 340)

KAJIMA CORPORATION CONTEST 2024(AtCoder Beginner Contest 340)

A - Arithmetic Progression

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
map<int, ll> q;

void solve()
{
    int a, b, c;
    cin >> a >> b >> c;
    while (a <= b)
    {
        cout << a << ' ';
        a += c;
    }
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

B - Append

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
map<int, ll> q;

void solve()
{
    int n;
    vector<int> v;
    cin >> n;
    while (n--)
    {
        int a, b;
        cin >> a >> b;
        if (a == 1)
        {
            v.push_back(b);
        }
        else
        {
            int m = v.size();
            cout << v[m - b] << endl;
        }
    }
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

C - Divide and Divide

解题思路:

可记忆化搜索。

除了最后一层得到1的拆分可能会有不同,前面的拆分层数都是一样的,花费总和也都是x

最后x一定会全部拆分成1,所以,我们可以先算出倒数第二层总共会有多少个数字,此时数字不是1就是2

然后二分得出有多少个2,这些就是最后一层的偏差,加上即可。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;

void solve()
{
    ll x;
    cin >> x;
    ll ans = 0;
    int cnt = 0;
    ll l = 0;
    ll r = 0;
    ll t = x;
    while (t >= 2)
    {
        l++;
        t /= 2;
    }
    t = x;
    while (t >= 2)
    {
        r++;
        t = (t + 1) / 2;
    }
    ans = x * l;
    ll s = 1ll << l;
    l = -1;
    r = s + 1;
    while (l + 1 < r)
    {
        ll mid = l + r >> 1;
        if (mid + 2 * (s - mid) < x)
        {
            r = mid;
        }
        else
        {
            l = mid;
        }
    }
    cout << 2 * (s - l) + ans << endl;
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

D - Super Takahashi Bros.

解题思路:

有环,不好dp

所以,直接跑最短路。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int N = 5e5 + 10;
const ll inf = 1ll << 60;
int e[N * 2];
int ne[N * 2];
int h[N];
ll w[N];
int idx;
ll dist[N];
bool vis[N];
int n;
void add(int a, int b, int c)
{
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

void dij()
{
    priority_queue<pii, vector<pii>, greater<pii>> q;
    q.push({dist[1], 1});
    dist[1] = 0;
    while (q.size())
    {
        auto t = q.top();
        q.pop();
        auto u = t.se;
        vis[u] = false;
        for (int j = h[u]; ~j; j = ne[j])
        {
            int v = e[j];
            if (dist[v] > dist[u] + w[j])
            {
                dist[v] = dist[u] + w[j];
                if (!vis[v])
                {
                    q.push({dist[v], v});
                }
            }
        }
    }
}

void solve()
{
    memset(h, -1, sizeof h);
    cin >> n;
    for (int i = 1; i < n; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(i, i + 1, a);
        add(i, c, b);
        dist[i] = inf;
    }
    dist[n] = inf;
    dij();
    cout << dist[n] << endl;
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

E - Mancala 2

解题思路:

单点查询+区间修改线段树可做。

修改区间讨论下即可。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int N = 2e5 + 10;
ll t[N * 8];
ll laz[N * 8];
int n, m;

void pushup(int u)
{
    t[u] = t[u << 1] + t[u << 1 | 1];
}

void pushdown(int u)
{
    if (laz[u])
    {
        t[u << 1] += laz[u];
        t[u << 1 | 1] += laz[u];
        laz[u << 1] += laz[u];
        laz[u << 1 | 1] += laz[u];
        laz[u] = 0;
    }
}

void insert(int u, int l, int r, int nl, int nr, ll val)
{
    if (l >= nl && r <= nr)
    {
        t[u] += val;
        laz[u] += val;
        return;
    }
    pushdown(u);
    int mid = l + r >> 1;
    if (nl <= mid)
    {
        insert(u << 1, l, mid, nl, nr, val);
    }
    if (nr > mid)
    {
        insert(u << 1 | 1, mid + 1, r, nl, nr, val);
    }
    pushup(u);
}

ll query(int u, int l, int r, int v)
{

    if (l == r)
    {
        return t[u];
    }
    pushdown(u);
    int mid = l + r >> 1;
    if (v <= mid)
    {
        return query(u << 1, l, mid, v);
    }
    return query(u << 1 | 1, mid + 1, r, v);
}

void print()
{
    for (int i = 0; i < n; i++)
    {
        cout << query(1, 0, n, i) << ' ';
    }
    cout << endl;
}

void solve()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        ll x;
        cin >> x;
        insert(1, 0, n, i, i, x);
    }

    while (m--)
    {
        int b;
        cin >> b;
        ll res = query(1, 0, n, b);
        insert(1, 0, n, b, b, -res);
        ll a = res / n;
        ll c = res % n;
        if (c != 0)
        {
            ll lr = n - 1 - (b + 1) + 1;
            if (c > lr)
            {
                insert(1, 0, n, b + 1, n - 1, 1);
                insert(1, 0, n, 0, c - lr - 1, 1);
            }
            else
            {
                insert(1, 0, n, b + 1, b + 1 + c - 1, 1);
            }
        }
        insert(1, 0, n, 0, n - 1, a);
    }
    print();
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

F - S = 1

解题思路:

首先根据叉乘可得出|xyab|=2

扩展欧几里得可求不定方程的一组可行解。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

void solve()
{
    ll a, b;
    cin >> a >> b;
    ll g = gcd(a, b);
    g = abs(g);
    if (g > 2)
    {
        puts("-1");
        return;
    }
    ll x = 0;
    ll y = 0;
    exgcd(a, -b, y, x);
    cout << x * 2 / g << ' ' << y * 2 / g << endl;
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}

G - Leaf Color

解题思路:

对于一棵叶子结点都是同一颜色的树,我们发现,只有该颜色的结点和这些结点的公共祖先是构成这样的树的有用元素,所以可以对于每种颜色构建虚树。

dp[i]:i

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const int N = 3e5 + 10;
const int mod = 998244353;
vector<int> e[N];
vector<int> adj[N];
int s[N];
int top;
int dfn[N];
int idx;
int n, q;
int dep[N];
int fa[N][22];
int k;
bool vis[N];
int c[N];
ll ans = 0;
ll f[N];
vector<int> color[N];

void dfs(int u, int par)
{
    fa[u][0] = par;
    dfn[u] = ++idx;
    for (auto v : e[u])
    {
        if (v == par)
        {
            continue;
        }
        dep[v] = dep[u] + 1;
        dfs(v, u);
    }
}

int lca(int a, int b)
{
    if (dep[a] < dep[b])
    {
        swap(a, b);
    }
    for (int i = 20; i >= 0; i--)
    {
        if (dep[fa[a][i]] >= dep[b])
        {
            a = fa[a][i];
        }
    }
    if (a == b)
    {
        return a;
    }
    for (int i = 20; i >= 0; i--)
    {
        if (fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0];
}

bool cmp(int a, int b)
{
    return dfn[a] < dfn[b];
}

void build(vector<int> a)
{
    sort(a.begin(), a.end(), cmp);
    top = 0;
    s[++top] = 1;
    if (a[0] != 1)
    {
        s[++top] = a[0];
    }
    for (int i = 1; i < a.size(); i++)
    {
        int l = lca(s[top], a[i]);
        while (top > 1 && dep[s[top - 1]] >= dep[l])
        {
            adj[s[top - 1]].push_back(s[top]);
            top--;
        }
        if (s[top] != l)
        {
            adj[l].push_back(s[top]);
            s[top] = l;
        }
        s[++top] = a[i];
    }
    while (top)
    {
        adj[s[top - 1]].push_back(s[top]);
        top--;
    }
}

void dp(int u, int col)
{
    f[u] = 1;
    for (auto v : adj[u])
    {
        dp(v, col);
        // 这里计算全集,子树可选(f[v)),可不选(+ 1)
        f[u] = f[u] * (f[v] + 1) % mod;
    }
    ll cur = f[u];
    if (c[u] != col)
    {
        cur--;
        // 不能一个子节点都不选。
        f[u]--;
        // 对于以u为最终根节点的情况来说,不能只选择一棵子树。
        for (auto v : adj[u])
        {
            cur = ((cur - f[v]) % mod + mod) % mod;
        }
    }
    ans = ((ans + cur) % mod + mod) % mod;
    adj[u].clear();
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &c[i]);
        color[c[i]].push_back(i);
    }
    for (int i = 1; i < n; i++)
    {
        int a, b, c;
        scanf("%d %d", &a, &b);
        e[a].push_back(b);
        e[b].push_back(a);
    }
    dep[1] = 1;
    dfs(1, 0);
    for (int j = 1; j <= 20; j++)
    {
        for (int i = 1; i <= n; i++)
        {
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if ((int)color[i].size() == 0)
        {
            continue;
        }
        build(color[i]);
        dp(1, i);
    }
    printf("%lld\n", ans);
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}
posted @   value0  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示