[LGR2021五月]题解

洛谷2021五月月赛题解


凑数

摸几下发现对于某一个 k,s 只要在一个区间内,他总是能被凑出来的,考虑这个区间左右端点,不过就是考虑最大值和最小值,可以想到最小值就是 [1,k] 的和,最大值就是 [n-k+1,n] 的和


Clear Up

还不会


猜树

有 1 为根节点,那么我们可以 O(n) 获得每一层的节点

然后考虑一层一层的搞,设相邻两层的节点数为 $n_i$ 和 $n_j$,我们有一个很显然的想法就是对于第 i 层的每一个节点,我们遍历所有的 j 层节点,并且用询问1搞出距离,这样距离为 1 的点就是他的儿子,复杂度 $O(n_in_j)$

可以发现这种做法可以被卡到 $O(n^2)$

考虑询问2来做这题

对于每一层的每一个节点,都询问他子树的节点。在这个点集里,位于下一层的节点就是他的儿子。那么复杂度是多少,我们可以发现在同一层里的询问是互不相交的,所以假设树有 k 层,总复杂度是 $O(kn)$

后者做法有一个好处,就是不管某一层有多少个点,他处理一层的复杂度总是 O(n)

那么两者结合一下,当用前者做法优于后者时,用前者做法,否则用后者做法,可以发现处理一层的复杂度是 $O(\min(n_in_j,n))$

那么总复杂度是多少?考虑最坏情况,每一层都是 $O(\sqrt n)$ 个节点,那么每一层都会被卡满到 O(n),但是我们这时只有 $O(\sqrt n)$ 层

所以总复杂度 $O(n\sqrt n)$

#include <ctime>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 5010
#define INF 0x7fffffff
#define ll long long

std::vector <int> depset[inf];
std::vector <int> q;
int n;
int maxdep;
int fa[inf], dep[inf];

inline int querydist(int x, int y) {
    printf("? 1 %d %d\n", x, y);
    fflush(stdout);
    int t; std::cin >> t;
    return t;
}

inline int querytree(int x) {
    printf("? 2 %d\n", x);
    fflush(stdout);
    q.clear();
    int sz, t; std::cin >> sz;
    for(int i = 1; i <= sz; i++) {
        std::cin >> t; q.push_back(t);
    }
    return sz;
}

inline void distfind(int d) {
    for(auto i: depset[d]) {
        for(auto j: depset[d + 1]) {
            int p = querydist(i, j);
            if(p == 1) fa[j] = i;
        }
    }
}

inline void treefind(int d) {
    for(auto i: depset[d]) {
        querytree(i);
        for(auto j: q) {
            if(dep[j] == d + 1) fa[j] = i;
        }
    }
}

signed main(){
    std::cin >> n;
    q.reserve(n);
    for(int i = 2; i <= n; i++) {
        int d = querydist(1, i);
        depset[d].push_back(i);
        dep[i] = d;
        maxdep = std::max (maxdep, d);
    }
    for(int i = 1; i < maxdep; i++) {
        if((int)(depset[i].size() * depset[i + 1].size()) < n) 
            distfind(i);
        else treefind(i);
    }
    for(auto i: depset[1]) fa[i] = 1;
    printf("! ");
    for(int i = 2; i <= n; i++) {
        printf("%d%c", fa[i], " \n"[i == n]);
    }
    fflush(stdout);
    return 0;
}

 

posted @ 2021-05-22 10:37  Chiaro  阅读(61)  评论(0)    收藏  举报