浙江省第十六屆大學生ACM程序設計競賽部分題解


 

E .Sequence in the Pocket

sol:將數組copy一份,然后sort一下,找尋后面最多多少個元素在原數組中保持有序,用總個數減去已經有序的就是我們需要移動的次數。

  • 思維題
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    int a[MAXN], b[MAXN];
    int main() {
        int t, n;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            sort(b + 1, b + 1 + n);
            int ans = n;
            for (int i = n; i >= 1; i--) 
                if (a[i] == b[ans]) ans--; 
            printf("%d\n", ans);
        }
        return 0;
    } 
    View Code

    一開始我思路錯了還浪費了一定時間。后來隊友提供了正確思路

F .Abbreviation

sol:首字母不刪直接輸出,剩下的逐個判斷。注意一下‘y’也是要刪的

  • 帶坑的簽到題
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 105;
    char s[MAXN];
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            scanf("%s", s);
            putchar(s[0]);
            for (int i = 1; s[i]; i++) 
                if (s[i] != 'a' && s[i] != 'e' && s[i] != 'i' && s[i] != 'o' && s[i] != 'u' && s[i] != 'y')
                    putchar(s[i]);
            puts("");
        }
        return 0;
    }
    View Code

     

G .Lucky 7 in the Pocket

sol:這題只要找7的倍數,所以可以直接暴力,如果是1e9 + 7這種比較大的數就不行了。既然可以暴力,那就采取最省時間的做法來一波暴力。

  • 暴力簽到題
    #include "bits/stdc++.h"
    using namespace std;
    int main() {
        int t, n;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            while (n % 7 != 0 || n % 4 == 0) n++;
            printf("%d\n", n);
        }
        return 0;
    }
    View Code

     

H .Singing Everywhere

sol:遍歷每個數,檢查刪除這個數可以減少多少高音。最后減一下就是結果

  • 暴力
    #include "bits/stdc++.h"
    using namespace std;
    typedef long long LL;
    const int MAXN = 1e5 + 5;
    const LL INF = 1LL << 60;
    LL arr[MAXN];
    int t, n;
    int getSub(int i) {
        int a = 0, b = 0;
        if (i != 1 && arr[i - 1] > arr[i - 2] && arr[i - 1] > arr[i]) a++;
        if (arr[i] > arr[i - 1] && arr[i] > arr[i + 1]) a++;
        if (i != n && arr[i + 1] > arr[i + 2] && arr[i + 1] > arr[i]) a++;
        if (i != 1 && arr[i - 1] > arr[i - 2] && arr[i - 1] > arr[i + 1]) b++;
        if (i != n && arr[i + 1] > arr[i + 2] && arr[i + 1] > arr[i - 1]) b++;
        return a - b; 
    }
    int main() {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            int ans = 0, sub = 0;
            for (int i = 1; i <= n; i++)
                scanf("%lld", &arr[i]);
            arr[0] = arr[n + 1] = INF;
            for (int i = 1; i <= n; i++) {
                if (arr[i] > arr[i - 1] && arr[i] > arr[i + 1]) ans++;
                sub = max(sub, getSub(i));
            }
            printf("%d\n", ans - sub);
        }
        return 0;
    }
    View Code

    因為題目的范圍完全就是int的極限范圍。一開始在兩邊補INF防越界的時候采用的0x3f3f3f3f不夠大還導致了一次wa,后來全部改成了long long。INF也改成了1LL << 60

I .Fibonacci in the Pocket

sol:因為fibonacci的奇偶性是三個一循環都是奇奇偶。而奇奇偶相加為偶數不影響結果。所以可以將a映射到1 - 3,b映射到4 - 6;然后從a加到b;

  • 數學+規律
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 10005;
    char s1[MAXN], s2[MAXN];
    bool is_odd[] = {0, 1, 1, 0, 1, 1, 0};
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            scanf("%s%s", s1, s2);
            int a = 0, b = 0, c = 0;
            for (int i = 0; s1[i]; i++) a += s1[i] ^ '0';
            for (int i = 0; s2[i]; i++) b += s2[i] ^ '0';
            a = (a - 1) % 3 + 1;
            b = (b - 1) % 3 + 4;
            for (int i = a; i <= b; i++)
                c += is_odd[i];
            printf("%d\n", c & 1);
        }
        return 0;
    }
    View Code

    3是一個神奇的數字。一個數模3等於這個數所有位數和模3。所有我們先把a和b所有位數和求出來。

J .Welcome Party

sol:簡單來說這題就是聯通塊和字典序,可以用並查集解決聯通塊,優先隊列解決字典序。

  • 圖算法
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e6 + 5;
    vector<int> edge[MAXN];
    priority_queue<int, vector<int>, greater<int> > que;
    int pre[MAXN]; bool vis[MAXN];
    void init(int n) {
        memset(pre, -1, sizeof(int) * (n + 1));
        memset(vis, false, sizeof(bool) * (n + 1));
        for (int i = 1; i <= n; i++) edge[i].clear();
    }
    int find(int k) {
        if (pre[k] == -1) return k;
        return pre[k] = find(pre[k]);
    }
    void bfs() {
        bool head = true;
        while (!que.empty()) {
            int k = que.top();
            que.pop();
            if (vis[k]) continue;
            vis[k] = true;
            if (head) {
                printf("%d", k);
                head = false;
            } else printf(" %d", k);
            for (int i = 0; i < edge[k].size(); i++) 
                que.push(edge[k][i]);
        }
        puts("");
    }
    int main() {
        int t, n, m;
        scanf("%d", &t);
        while (t--) {
            scanf("%d%d", &n, &m);
            init(n);
            int a, b, fa, fb;
            while (m--) {
                scanf("%d%d", &a, &b);
                edge[a].push_back(b);
                edge[b].push_back(a);
                fa = find(a);
                fb = find(b);
                if (fa == fb) continue;
                if (fa < fb) pre[fb] = fa;
                else pre[fa] = fb;
            }
            for (int i = 1; i <= n; i++)
                if (pre[i] == -1) que.push(i);
            printf("%d\n", que.size());
            bfs();
        }
        return 0;
    } 
    View Code

    第一發提交PE了,以為都是最后判PE的,改了PE就能AC了。然后第二發因為沒有排字典序wa。之后又因為沒明白“It is guaranteed that neither the sum of n nor the sum of m of all cases will exceed 1e6.”而各種超時。(處理pre和vis的時候清空了整個數組)其實最后也沒明白這句話。后來一通亂改在最后8分鍾AC了。錯失冠軍;

K .Strings in the Pocket

sol:如果兩個串相同,可以視為找回文串個數。如果不同,先判斷刪除左邊連續相同部分和右邊連續相同部分后能否通過反轉使兩串相等,如果不行結果為0,如果可行不斷往兩邊延伸。

  • 思維+回文串
    #include "bits/stdc++.h"
    using namespace std;
    typedef long long LL;
    const int MAXN = 2e6 + 5;
    char s1[MAXN << 1], s2[MAXN];
    int p[MAXN << 1];
    LL manacher(char* s, int* p) {
        int n = strlen(s);
        for (int i = n; i >= 0; i--) {
            s[i + 1 << 1] = s[i];
            s[i << 1 | 1] = '#';
        }
        n = n + 1 << 1;
        s[0] = '$';
        int k = 0; LL ans = 0;
        for (int i = 2; i < n; i++) {
            if (i >= k + p[k]) p[i] = 1;
            else p[i] = min(p[2 * k - i], p[k] + k - i);
            while (s[i + p[i]] == s[i - p[i]]) p[i]++;
            if (p[i] + i > p[k] + k) k = i;
            ans += p[i] >> 1;
        }
        return ans;
    }
    int getAns(char* s1, char* s2) {
        int n = strlen(s1);
        int l = 0, r = n - 1;
        while (s1[l] == s2[l]) l++;
        while (s1[r] == s2[r]) r--;
        int a = l, b = r;
        while (a <= r) {
            if (s1[a] != s2[b]) return 0;
            a++, b--;
        }
        int ans = 0;
        do {
            ans++;
            l--, r++;
        } while (l >= 0 && r < n && s1[l] == s1[r]);
        return ans;
    }
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            scanf("%s%s", s1, s2);
            if (strcmp(s1, s2)) printf("%d\n", getAns(s1, s2));
            else printf("%lld\n", manacher(s1, p)); 
        }
        return 0;
    } 
    View Code

    可能是自信不夠,壓根不相信專科能做那么多題,不相信這題這么簡單。思維部分隊友已經講透了,算法部分我也會敲。然而就是沒做出來,錯失特獎。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM