Codeforces Round #686 (Div. 3)题解

A

题意:给你一个n,求一个长度为n的排列p,使得\(p[i]!=i\)
做法:reverse一下,然后如果n为奇数,那么swap(p[1], p[(n+1)/2]);

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n;
        scanf("%d", &n);
        if (n & 1) {
            for (int i = 1; i <= n; i++) {
                if (i == 1) printf("%d ", (n + 1) / 2);
                else if (i == (n + 1) / 2) printf("%d ", n);
                else printf("%d ", n - i + 1);
            }
        }
        else for (int i = 1; i <= n; i++) printf("%d ", n - i + 1);
        puts("");
    }
    return 0;
}

B

题意:给一个长度为n的数组a(1<=ai<=n),求其中只出现过一次的数中最小数的下标,没有的话输出-1
做法:把数字丢到桶里,然后从小到大for一遍,找到最小的数的值,再在a中for一遍找出下标(这里也可以用pos[i]表示值为i的数的下标,然后直接输出)
注意,多测清空不要用memset,第一发被卡T了

#include <bits/stdc++.h> 
#define maxn 200005
int n, a[maxn], cnt[maxn];
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) cnt[i] = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            ++cnt[a[i]];
        }
        int v;
        bool fl = 0;
        for (int i = 1; i <= n; i++) {
            if (cnt[i] == 1) {
                fl = 1;
                v = i;
                break;
            }
        }
        if (!fl) puts("-1");
        else {
            for (int i = 1; i <= n; i++) if (a[i] == v) {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

C

题意:好麻烦,自己看(
做法:开n个vector
对于vector[i]表示哪些下标的值为i,然后算一下空隙vector[i][j]与vector[i][j-1]之间有没有元素,有的话cnt[i]++
最后\(ans=min_{1 \leq i \leq n}{cnt_i}\)

#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
int n;
vector<int> pos[maxn];
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) pos[i].clear();
        for (int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            pos[x].push_back(i);
        }
        int ans = n;
        for (int i = 1; i <= n; i++) if (!pos[i].empty()) {
            int cnt = 0;
            for (int j = 1; j < pos[i].size(); j++)
                if (pos[i][j] - pos[i][j - 1] > 1) cnt++;
            ans = min(ans, cnt + (pos[i].front() != 1) + (pos[i].back() != n));
        }
        printf("%d\n", ans);
    }
    return 0;
}

D

题意:给你一个n,求出一个长度为k的序列a,使得\(\prod_{i=0}^k a_i = n\),且a[i]|a[i+1]且k最大(a[i]!=1)
做法:考虑n质因数分解后为\({p_1}^{e_1} {p_2}^{e_2}...{p_m}^{e_m}\)
则答案为\(e_mx=max_{1 \leq i \leq m}{e_i}\)
证明:
因为\(\prod_{i=0}^k a_i = n\),所以题目就相当于把n质因数分解后的每个值分配给a[1]~a[k]
因为a[i]|a[i+1],所以a[i+1]分到的每项一定是大于等于a[i]分到的
那肯定取等于最赚,但是你每次至少要分出来1。
所以答案不超过\(e_mx\)
你构造一个长度为\(e_mx\)的序列,使得a[1]~a[\(e_mx-1\)]都等于p_mx,a[\(e_mx\)]=剩下的数乘起来
这样就构造除了长为\(e_mx\)的序列,完事

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        ll n;
        scanf("%lld", &n);
        int mxc = 0;
        ll mxv = 0;
        for (ll i = 2; i * i <= n; i++) {
            int cnt = 0;
            while (n % i == 0) {
                n /= i;
                cnt++;
            }
            if (cnt > mxc) mxc = cnt, mxv = i;
        }
        printf("%d\n", max(mxc, 1));
        if (mxc > 1) {
            for (int i = 1; i <= mxc - 1; i++) printf("%lld ", mxv);
            printf("%lld\n", (n / (ll)pow(mxv, mxc - 1)));
        }
        else printf("%lld\n", n); 
    }
    return 0;
}
上一篇:MXC抹茶:区块链技术将赋能个人数据保护


下一篇:MXC抹茶:BAT在区块链金融的布局情况