2019 Multi-University Training Contest 4

虽然13分钟切完08给了极大自信,但是07又给了我当头一棒…
1001 AND Minimum Spanning Tree

解法:对于每个数,我们找它二进制下最右边第一个0即可,签到
#include
using namespace std;
const int maxn = 1e6 + 10;
int ans[maxn];
int main() {
    int T;
    cin>>T;
    while (T--) {
        int n;
        cin>>n;
        for (int i = 1; i <= n; i++)
            p[i] = i;
        int res = 0;
        for (int i = 1; i <= n; i++) {
            int flag = -1;
            for (int j = 0; (1 << j) <= n; j++)
                if (!(i >> j & 1)) {
                    flag = (1 << j);
                    break;
                }
            if (flag == -1)
                ans[i] = 1, res += 1;
            else
                ans[i] = flag;
        }
        printf("%d\n", res);
        for (int i = 2; i <= n; i++)
            printf("%d%c", ans[i], (i == n) ? ' \n' : ' ');
    }
}

1003 Divide the Stones

解法:假设n/k为偶数,举个例子:1 2 3 4 5 6,k = 3,那么很显然 1 和 6 放一组,2 和 5 一组 ,3 和 4 一组,如果 n / k 为奇数,那么怎么放呢?其实仔细分析也不能,举个例子:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15,k = 5,我们从15枚举到11,15 可以和1,8放一起,13可以和2,9放一起,11可以和3,10放一起,14 可以和6,4一组,12可以和7,5一组,相信你也能发现规律了吧
#include
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
vector<int> G[maxn];
int main() {
    int Cas;
    scanf("%d", &Cas);
    while (Cas--) {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= k; i++)
            G[i].clear();
        if (k == 1) {
            puts("yes");
            for (int i = 1; i <= n; i++)
                printf("%d%c", i, (i == n) ? '\n' : ' ');
            continue;
        }
        int m = n / k;
        if ((n / k) % 2 == 0) {
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= k; j++) {
                    int v = (i - 1) * k + j;
                    int cur = j;
                    if (i % 2 == 0)
                        cur = k + 1 - j;
                    G[cur].push_back(v);
                }
            }
            puts("yes");
            for (int i = 1; i <= k; i++)
                for (int j = 0; j < G[i].size(); j++)
                    printf("%d%c", G[i][j], (j == G[i].size() - 1) ? '\n' : ' ');
            continue;
        }
        int ok = 1;
        for (int i = 4; i <= m; i++) {
            for (int j = 1; j <= k; j++) {
                int v = (i - 1) * k + j;
                int cur = j;
                if (i % 2 == 0)
                    cur = k + 1 - j;
                G[cur].push_back(v);
            }
        }
        ll T = 1ll * (1 +  3 * k) * (3 * k) / 2;
        if (T % k)
            ok = 0;
        if (ok) {
            T /= k;
            for (int i = 3 * k; i > 2 * k; i--) {
                int cur = i % k;
                if (!cur)
                    cur = k;
                cur = k - cur + 1;
                G[cur].push_back(i);
                ll tmp = T - i;
                if (cur % 2) {
                    int tmp2 = cur / 2;
                    G[cur].push_back(tmp2 + 1);
                    G[cur].push_back(tmp - tmp2 - 1);
                }
                else {
                    int tmp2 = cur / 2 + k;
                    G[cur].push_back(tmp2);
                    G[cur].push_back(tmp - tmp2);
                }
            }
        }

        if (!ok)
            puts("no");
        else {
            puts("yes");
            for (int i = 1; i <= k; i++)
                for (int j = 0; j < G[i].size(); j++)
                    printf("%d%c", G[i][j], (j == G[i].size() - 1) ? '\n' : ' ');
        }
    }
}

1006 Horse
待补
1007 Just an Old Puzzle
这个题的难度不应该这么多人ac啊…
1008 K-th Closest Distance

解法:首先先建立可持久化线段树,二分答案ans,然后从线段树中查询[p - ans, p + ans]的区间和是否大于等于k即可。
#include
using namespace std;
const int maxn = 1e5 + 10, N = 1e6;
int rt[maxn], ls[maxn * 22], rs[maxn * 22], sum[maxn * 22], cnt;
#define m (l + r) / 2
void up(int &o, int pre, int l, int r, int k) {
    o = ++cnt;
    sum[o] = sum[pre] + 1;
    ls[o] = ls[pre];
    rs[o] = rs[pre];
    if (l == r)
        return;
    if (k <= m)
        up(ls[o], ls[pre], l, m, k);
    else
        up(rs[o], rs[pre], m + 1, r, k);
}
int qu(int o, int pre, int l, int r, int ql, int qr) {
    if (l >= ql && r <= qr)
        return sum[o] - sum[pre];
    int res = 0;
    if (ql <= m)
        res += qu(ls[o], ls[pre], l, m, ql, qr);
    if (qr > m)
        res += qu(rs[o], rs[pre], m + 1, r, ql, qr);
    return res;
}
int gao(int x, int len, int l, int r) {
    int L = max(x - len, 1);
    int R = min(x + len, N);
    return qu(rt[r], rt[l - 1], 1, N, L, R);
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, q, x, l, r, p, k, ans = 0;
        cnt = 0;
        scanf("%d%d", &n, &q);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &x);
            up(rt[i], rt[i - 1], 1, N, x);
        }
        while (q--) {
            scanf("%d%d%d%d", &l, &r, &p, &k);
            l ^= ans, r ^= ans, p ^= ans, k ^= ans;
            int L = 0, R = 1e6;
            while (L < R) {
                int mid = (L + R) / 2;
                if (gao(p, mid, l, r) < k)
                    L = mid + 1;
                else
                    R = mid;
            }
            printf("%d\n", ans = L);
        }
    }
}

1010 Minimal Power of Prime

解法:对于每个数n,我们枚举10000以内的素数,然后把 n 去分解质因数,如果 n 分解完不为1,那么有4种情况,n是一个质数的4次方,n是一个质数的3次方,n是一个质数的2次方,n是一个或多个不同质数相乘得到,分别判断一下即可
#include
#define ll long long
using namespace std;
const int maxn = 1e4 + 100;
int vis[maxn], pri[maxn], cnt;
void init(int n) {
    for (int i = 2; i <= n; i++) {
        if (!vis[i])
            pri[++cnt] = i;
        for (int j = 1; j <= cnt && pri[j] * i <= n; j++) {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0)
                break;
        }
    }
}
ll gao(ll x, int y) {
    ll res = 1;
    while (y) {
        res *= x;
        y--;
    }
    return res;
}
int main() {
    int T;
    scanf("%d", &T);
    init(maxn - 1);
    while (T--) {
        ll n;
        scanf("%lld", &n);
        int ans = 199;
        for (int i = 1; i <= cnt && pri[i] <= n; i++)
        if (n % pri[i] == 0) {
            int res = 0;
            while (n % pri[i] == 0)
                res++, n /= pri[i];
            ans = min(ans, res);
        }
        if (n == 1) {
            printf("%d\n", ans);
            continue;
        }
        int x = pow(n, 1.0 / 4);
        if (gao(x, 4) == n || gao(x + 1, 4) == n || gao(x - 1, 4) == n)
            ans = min(ans, 4);
        else {
            x = pow(n, 1.0 / 3);
            if (gao(x, 3) == n || gao(x + 1, 3) == n || gao(x - 1, 3) == n)
                ans = min(ans, 3);
            else {
                int x = pow(n, 0.5);
                if (gao(x, 2) == n || gao(x + 1, 2) == n || gao(x - 1, 2) == n)
                    ans = min(ans, 2);
                else
                    ans = 1;
            }
        }
        printf("%d\n", ans);
    }
}

你可能感兴趣的:(数据结构----线段树,杭电多校)