3月28日abc补题

C. understory

依旧数据结构爱好者()
用multiset
image
erase可以删除从a迭代器到b迭代器的数,也就是说这个题可以upper_bound找出迭代器,删除begin到该迭代器的数。
size返回的是一共多少数(也就是有重复的

D Concat Power of 2

观察样例,发现1e9内符合条件的大约是1e6这个数据范围,所以直接暴力,先把1e9内所有的2的幂找出来存进数组里,这是组成我们想要的数的基础。

用一个优先队列小根堆,确保从小到大遍历,每一次从堆顶取出元素然后与2的幂数组进行组合,同时记录队列pop的次数就行了,当cnt=n的时候,就可以输出结束了。

注意 如果用字符串拼接,你将会使用stoll或者to_string,这个时间复杂度是O(n) 的,所以会超时
所以用ksm计算10的幂次方,与前一个数相乘在与后一个数相加。

vs a;
set<int> p;
priority_queue<int, vi, greater<>> q;
void init()
{
    int now = 1;
    while (now <= 1e9)
    {
        string str = to_string(now);
        q.push(now);
        p.insert(now);
        a.push_back(str);
        now <<= 1;
    }
}
void solve()
{
    init();
    cin >> n;
    int cnt = 0;
    while (q.size())
    {
        auto cur = q.top();
        q.pop();
        cnt++;
        if (cnt == n)
        {
            cout << cur << endl;
            return;
        }

        string str = to_string(cur);
        for (auto &i : a)
        {
            int u = i.size();
            int v = stoll(i);
            int shu = cur * ksm(10, u, MOD) + v;

            if (shu > 1e9 || p.count(shu))
            {
                continue;
            }
            q.push(shu);
            p.insert(shu);
        }
    }
}

还有一种表现形式是这样的
476fb30bd40112ec2b73cf8ae70dab2c

E Tree Distance

image

不难发现,题目要求建一个树,而且这个树上任意两点的最小距离必须符合他给出的值才可以,我们可以用最小生成树生成这个树。
然后对这个树每个点跑最短路,然后看看是否符合标准,如果不符合直接输出No 返回。

处理完每个点如果还没有返回说明这棵树符合条件,那么输出Yes .

// 并查集
int fa[M];
void init()
{
    for (int i = 1; i < M; i++)
    {
        fa[i] = i;
    }
}
int find(int a)
{
    return a == fa[a] ? a : fa[a] = find(fa[a]);
}
bool same(int a, int b)
{
    return find(a) == find(b);
}
void join(int a, int b)
{
    a = find(a);
    b = find(b);
    if (a != b)
    {
        fa[a] = b;
    }
}
struct node
{
    int u, v, val;
} a[4500005];
bool cmp(node a, node b)
{
    return a.val < b.val;
}
struct op
{
    int to, w;
};
vector<op> adj[M];
int dis[3003][3003];
int arr[3003][3003];
void solve()
{
    init();
    cin >> n;
    int cnt = 0;
    for (int i = 1; i < n; i++)
    {
        for (int j = i + 1; j <= n; j++)
        {
            cin >> a[cnt].val;
            arr[i][j] = a[cnt].val;
            a[cnt].u = i;
            a[cnt].v = j;
            cnt++;
        }
    }
    sort(a, a + cnt, cmp);
    int num = 0;
    for (int i = 0; i <= cnt; i++)
    {
        if (same(a[i].u, a[i].v))
        {
            continue;
        }
        else
        {
            num++;
            join(a[i].u, a[i].v);
            adj[a[i].u].push_back({a[i].v, a[i].val});
            adj[a[i].v].push_back({a[i].u, a[i].val});
        }
    }
    int ok = 0;
    for (int i = 1; i <= n; i++)
    {
        if (fa[i] == i)
        {
            ok++;
        }
    }
    if (ok != 1 || num != n - 1)
    {
        cout << "No" << endl;
        return;
    }
    for (int i = 1; i <= n; i++)
    {
        vi ans(n + 1, 1e18);
        ans[i] = 0;
        priority_queue<pii, vector<pii>, greater<>> p;
        p.push({0, i});
        while (!p.empty())
        {
            auto [w, v] = p.top();
            p.pop();
            if (w > ans[v])
            {
                continue;
            }
            for (auto [d, j] : adj[v])
            {
                if (w + j < ans[d])
                {
                    ans[d] = j + w;
                    p.push({ans[d], d});
                }
            }
        }
        for (int j = i + 1; j <= n; j++)
        {
            if (arr[i][j] != ans[j])
            {
                cout << "No" << endl;
                return;
            }
        }
    }
    cout << "Yes" << endl;
}

F Make Bipartite 3

8e618c17e87dfaa15e4ba75773c41fbe

显而易见的二分图,我对二分图的理解就是分左右两边,左边只能连右面,双方内部不能互相连

这个题每个点有黑白两种状态,类似于tWo-set问题,我们可以用扩展域并查集来维护黑白两个信息,1-n为黑,n+1-2n为白,读入两个点,先判断两个点是否已经在一个集合中了,如果是,那么这个图就废了,之后也不可能满足,然后在判断u和v+n是否已经在一个集合中,如果没有才需要进行合并。

如何求出每次询问时的黑色点个数?
可以将黑色点的权值设为1,白色设为0。
那么合并的时候肯定是选两个集合中权值少的作为黑色集合。
这样会有一个问题,那就是每次合并的时候,因为之前的集合也是合并而来,所以如果直接处理新集合肯定不对,所以先对老集合进行处理,分别减去u,v两点所对应的两个黑白集合的权值较小的集合,然后加上较小的新权值。

int fa[M * 2];
int sz[M * 2];
void init()
{
    for (int i = 1; i <= n; i++)
    {
        sz[i] = 1;
    }
    for (int i = 1; i <= 2 * n; i++)
    {
        fa[i] = i;
    }
}
int find(int a)
{
    return a == fa[a] ? a : fa[a] = find(fa[a]);
}
bool same(int a, int b)
{
    return find(a) == find(b);
}
void join(int a, int b)
{
    a = find(a);
    b = find(b);
    if (a != b)
    {
        fa[a] = b;
        sz[b] += sz[a];
    }
}
void solve()
{

    int q;
    cin >> n >> q;
    int ans = 0;
    int ok = 1;
    init();
    while (q--)
    {
        int u, v;
        cin >> u >> v;
        if (!ok)
        {
            cout << -1 << endl;
            continue;
        }
        if (find(u) == find(v))
        {
            ok = 0;
            cout << -1 << endl;
            continue;
        }
        if (!same(u, v + n))
        {
            ans -= min(sz[find(u)], sz[find(u + n)]);
            ans -= min(sz[find(v)], sz[find(v + n)]);
            join(u, v + n);
            join(v, u + n);
            ans += min(sz[find(u)], sz[find(u + n)]);
        }
        cout << ans << endl;
    }
}
posted @ 2026-03-28 22:07  Lambda_L  阅读(3)  评论(0)    收藏  举报