AtCoder Beginner Contest 340 A-G

A

按照等差数列直接模拟即可

void solve()
{
    int a, b, d;
    cin >> a >> b >> d;
    for (int i = a; i <= b; i += d)
        cout << i << " ";
    cout << endl;
}

B

模拟

void solve()
{
    int q;
    cin >> q;
    vector<int> a;

    int opt, x;
    while (q--)
    {
        cin >> opt >> x;
        if (opt == 1)
            a.push_back(x);
        else
        {
            cout << a[a.size() - x] << endl;
        }
    }
}

C

如果直接模拟肯定会超时,考虑用set维护种类,map维护数量,这样可以保证每种数只会被操作一次

void solve()
{
    ll n;
    cin >> n;
    map<ll, ll> mp;
    mp[n] = 1;
    set<ll> s;
    s.insert(n);
    ll res = 0;
    while (s.size() && *s.rbegin() >= 2)
    {
        ll t = *s.rbegin();
        ll num = mp[t];
        s.erase(*s.rbegin());
        res += t * num;
        if (t % 2 == 0)
        {
            s.insert(t / 2);
            mp[t / 2] += num * 2;
        }
        else
        {
            ll lo = t / 2, hi = (t - 1) / 2 + 1;
            if (lo >= 2)
                s.insert(lo), mp[lo] += num;
            if (hi >= 2)
                s.insert(hi), mp[hi] += num;
        }
    }
    cout << res << endl;
}

D

dijkstra板子

void solve()
{
    int n;
    cin >> n;
    vector<vector<pll>> e(n + 1);
    for (int i = 1; i < n; i++)
    {
        int a, b, x;
        cin >> a >> b >> x;
        e[i].push_back({i + 1, a});
        e[i].push_back({x, b});
    }
    auto dij = [&](int s) -> ll
    {
        vector<ll> dist(n + 1, 1e18);
        vector<bool> st(n + 1, 0);
        priority_queue<pll, vector<pll>, greater<pll>> q;
        dist[s] = 0;
        q.push({0, s});
        while (q.size())
        {
            auto t = q.top();
            q.pop();
            if (st[t.y])
                continue;
            st[t.y] = true;
            for (auto [to, w] : e[t.y])
                if (dist[t.y] + w < dist[to])
                    dist[to] = dist[t.y] + w, q.push({dist[to], to});
        }
        return dist[n];
    };
    cout << dij(1) << endl;
}

E

模拟,用树状数组维护差分数组,就可以实现区间加,单点查询

struct BIT
{
    int n;
    vector<ll> a;
    BIT(int _n) : n(_n + 3), a(n + 1) {}
    int lb(int x) { return x & -x; }
    void build(int n, vector<ll> &s)
    {
        for (int i = 1; i <= n; i++)
        {
            a[i] += s[i];
            int fa = i + lb(i);
            if (fa <= n)
                a[fa] += a[i];
        }
    }
    void add(int x, ll y)
    {
        for (; x < n; x += lb(x))
            a[x] += y;
    }
    ll query(int x)
    {
        ll res = 0;
        for (; x; x ^= lb(x))
            res += a[x];
        return res;
    }
};
void solve()
{
    int n, m;
    cin >> n >> m;
    vector<ll> a(n + 1), b(m + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= m; i++)
        cin >> b[i];
    BIT bit(n + 10);
    for (int i = 1; i <= n; i++)
        bit.add(i, a[i]), bit.add(i + 1, -a[i]);
    for (int i = 1; i <= m; i++)
    {
        int u = b[i] + 1;
        ll num = bit.query(u);
        bit.add(u, -num), bit.add(u + 1, num);
        ll add = num / n;
        bit.add(1, add), bit.add(n + 1, -add);
        num %= n;
        if (u + num <= n)
            bit.add(u + 1, 1), bit.add(u + num + 1, -1);
        else
        {
            bit.add(u + 1, 1), bit.add(n + 1, -1);
            num -= n - u;
            bit.add(1, 1), bit.add(num + 1, -1);
        }
    }
    for (int j = 1; j <= n; j++)
        cout << bit.query(j) << " ";
    cout << endl;
}

F

考虑用向量来计算面积,类似22桂林的E题,设未知点为\((ax,ay)\),那么可以得到:
\(ax*y-ay*x=2\)
用exgcd计算即可

```cpp
ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}
void solve()
{
    ll x, y;
    cin >> x >> y;
    pll t = {x, y};
    ll ansx, ansy;
    ll g = exgcd(-t.y, t.x, ansx, ansy);
    if (2 % g)
        cout << "-1" << endl;
    else
    {
        ll mul = 2 / g;
        cout << ansx * mul << " " << ansy * mul << endl;
    }
}

G

1.虚树dp
存一下同种颜色的点,对每种颜色建虚树
在虚树上dp答案
dp[u]表示以u为根的树,所有叶子节点是同种颜色(设为k)的方案数
$dp_u= {\textstyle \prod_{to \in son(i)} (f[to]+1)} $加一是因为可以不选
但是这样是不对的,因为如果当前点u的颜色与k不同:

1.它自己一个点肯定是不对的,要减去一(87,88行)
2.u和某一个儿子构成的树也是不对的,这样u成叶子了,要减去\(f[to]\)(90,91)

void solve()
{
    ll n, tot = 0, ans = 0;
    cin >> n;
    vector<int> a(n + 1), dfn(n + 1, 1), dist(n + 1, 0);
    vector<vector<ll>> to(n + 1, vector<ll>(20, 0));
    vector<vector<int>> e(n + 1), col(n + 1), ne(n + 1);
    vector<ll> f(n + 1, 0);
    vector<int> c;
    for (int i = 1; i <= n; i++)
        cin >> a[i], col[a[i]].push_back(i);
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
    }
    auto dfs = [&](auto dfs, int u, int fa) -> void
    {
        dfn[u] = ++tot;
        to[u][0] = fa;
        for (auto to : e[u])
            if (to != fa)
            {
                dist[to] = dist[u] + 1;
                dfs(dfs, to, u);
            }
    };
    dfs(dfs, 1, 0);
    for (int j = 1; j < 20; j++)
        for (int i = 1; i <= n; i++)
        {
            if (to[i][j - 1])
                to[i][j] = to[to[i][j - 1]][j - 1];
        }
    auto lca = [&](int u, int v) -> int
    {
        if (dist[u] < dist[v])
            swap(u, v);
        int cha = dist[u] - dist[v];
        for (int j = 0; j < 20 && cha; j++, cha /= 2)
            if (cha & 1)
                u = to[u][j];
        if (u != v)
        {
            for (int j = 19; j >= 0; j--)
                if (to[u][j] != to[v][j])
                    u = to[u][j], v = to[v][j];
            return to[u][0];
        }
        return u;
    };
    auto build = [&](int i) -> void
    {
        sort(col[i].begin(), col[i].end(), [&](int a, int b)
             { return dfn[a] < dfn[b]; });
        c.push_back(1);
        for (int j = 0; j + 1 < col[i].size(); j++)
        {
            c.push_back(col[i][j]);
            c.push_back(lca(col[i][j], col[i][j + 1]));
        }
        c.push_back(col[i].back());
        sort(c.begin(), c.end(), [&](int a, int b)
             { return dfn[a] < dfn[b]; });
        c.erase(unique(c.begin(), c.end()), c.end());
        for (int i = 0; i + 1 < c.size(); i++)
        {
            ll lc = lca(c[i], c[i + 1]);
            ne[lc].push_back(c[i + 1]);
            ne[c[i + 1]].push_back(lc);
        }
    };

    auto dp = [&](auto dp, int u, int fa, int k) -> void
    {
        f[u] = 1;
        for (auto to : ne[u])
            if (to != fa)
            {
                dp(dp, to, u, k);
                f[u] = f[u] * (f[to] + 1) % mod;
            }
        ll res = f[u];
        if (a[u] != k)
        {
            res = (res - 1 + mod) % mod;
            f[u] = (f[u] - 1 + mod) % mod;
            for (auto to : ne[u])
                if (to != fa)
                    res = (res - f[to] + mod) % mod;
        }
        ans = (ans + res) % mod;
    };
    for (int i = 1; i <= n; i++)
        if (col[i].size())
        {
            build(i);
            dp(dp, 1, 0, i);
            for (auto t : c)
                f[t] = 0, ne[t].clear();
            c.clear();
        }
    cout << ans << endl;
}

2.启发式合并

void solve()
{
    ll ans = 0;
    int n;
    cin >> n;
    vector<int> a(n + 1);
    vector<vector<int>> e(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
    }
    auto dfs = [&](auto dfs, int u, int fa) -> map<ll, ll>
    {
        map<ll, ll> fmp;
        for (auto to : e[u])
            if (to != fa)
            {
                auto smp = dfs(dfs, to, u);
                ans = (ans + smp[a[u]]) % mod; // u 与to 组成树
                if (fmp.size() < smp.size())
                    swap(fmp, smp);
                for (auto [col, sz] : smp)
                {
                    ans = (ans + fmp[col] * sz % mod) % mod;
                    fmp[col] = ((fmp[col] + 1) * (sz + 1) % mod - 1 + mod) % mod;
                }
            }
        fmp[a[u]] = (fmp[a[u]] + 1) % mod;
        ans = (ans + 1) % mod; // u自己作为树
        return fmp;
    };
    dfs(dfs, 1, 0);
    cout << ans << endl;
}
posted @ 2024-02-10 21:52  0x3ea  阅读(62)  评论(0编辑  收藏  举报