1. 程式人生 > 實用技巧 >Codeforces Round #686 (Div. 3)題解

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;
}