Loading

11.22 NOIP 模拟赛 T1. 破乱的诗歌

思路

场上考虑的其实很有道理来着

考虑左右字符集已经相同的情况是简单的
否则一定要把左右字符集调整到相同

那我们首先不难发现一个至少要使用的区间, 计算方法比较复杂, 但是宗旨是把左右字符集调整到相同且可匹配的必要花费
然后我们应该拓展长的那一端, 直到字符集相同之后可以考虑断开, 以此来获得最优解

#include <bits/stdc++.h>
#define int long long
#define rs rrt, mid + 1, r
#define mid ((l + r) >> 1)
#define ls lrt, l, mid
#define lrt rt << 1
#define rrt lrt | 1

char s[1000005];
std::vector <int> pos[26];
int n, cnt[26], num[26], id[26];
int ans = 0, m;

signed main () {
    scanf("%lld%s", &n, s + 1); m = (n + 1) / 2;
    for (int i = 1; i <= n; i++) cnt[s[i] - 'a']++;
    for (int i = 1; i <= n; i++) pos[s[i] - 'a'].push_back (i);
    int L = n / 2 + 1, R = m;
    memset (num, 0, sizeof num);
    for (int i = 1; i <= n / 2; i++) num[s[i] - 'a']++;
    for (int i = 0; i < 26; i++) if (num[i] > cnt[i] / 2)
        L = std::min (L, pos[i][cnt[i] / 2]);
    memset (num, 0, sizeof num);
    for (int i = n; i > m; i--) num[s[i] - 'a']++;
    for (int i = 0; i < 26; i++) if (num[i] > cnt[i] / 2)
        R = std::max (R, pos[i][cnt[i] / 2 - 1]);
    ans = R - L + 1;
    
    /*先换过来*/
    std::vector<int> chg1, chg2; chg1.clear(), chg2.clear();
    memset (num, 0, sizeof num);
    for (int i = 1; i <= n / 2; i++) num[s[i] - 'a']++;
    for (int i = 1; i <= n / 2; i++) if (num[s[i] - 'a'] > cnt[s[i] - 'a'] / 2) chg1.push_back(i), num[s[i] - 'a']--;
    memset (num, 0, sizeof num);
    for (int i = n; i > m; i--) num[s[i] - 'a']++;
    for (int i = n; i > m; i--) if (num[s[i] - 'a'] > cnt[s[i] - 'a'] / 2) chg2.push_back(i), num[s[i] - 'a']--;
    for (int i = 0; i < chg1.size(); i++) { int p1 = chg1[i], p2 = chg2[i]; std::swap(s[p1], s[p2]); }
    
    memset (num, 0, sizeof num);
    for (int i = 1; i <= n / 2; i++) num[s[i] - 'a']++;
    for (int i = n; i > m; i--) num[s[i] - 'a']--;
    int ccnt0 = 0;
    for (int i = 0; i < 26; i++) ccnt0 += (num[i] == 0);
//    std::cout << ccnt0 << ' ';
    
    if (R - m > n / 2 - L + 1) {
//        std::cout << "#1: ";
        int len = R - m;
        memset (num, 0, sizeof num);
        int cnt0 = 0;
        for (int i = m + 1; i <= R; i++) num[s[i] - 'a']++;
        for (int i = n / 2 - len + 1; i <= n / 2; i++) num[s[i] - 'a']--;
        for (int i = 0; i < 26; i++) cnt0 += (num[i] == 0);
        
        int l = n / 2 - len + 1, r = R;
        while (cnt0 != 26 && l > 1 && r < n) {
            l--, r++; 
            if (s[l] != s[r]) {
                if (num[s[l] - 'a'] == 0) cnt0--;
                if (num[s[r] - 'a'] == 0) cnt0--;
                if (++num[s[l] - 'a'] == 0) cnt0++;
                if (--num[s[r] - 'a'] == 0) cnt0++;
            }
            ans++;
        }
        while (l > 1 && r < n) {
            l--, r++;
            if (s[l] != s[r]) {
                num[s[l] - 'a']++, num[s[r] - 'a']--; cnt0 = 24;
                ans++;
                while (cnt0 != 26 && l > 1 && r < n) {
                    l--, r++; 
                    if (s[l] != s[r]) {
                        if (num[s[l] - 'a'] == 0) cnt0--;
                        if (num[s[r] - 'a'] == 0) cnt0--;
                        if (++num[s[l] - 'a'] == 0) cnt0++;
                        if (--num[s[r] - 'a'] == 0) cnt0++;
                    }
                    ans++;
                }
            }
        }
        printf("%lld", ans);
    } else {
//        std::cout << "#2: ";
        int len = n / 2 - L + 1;
        memset (num, 0, sizeof num);
        int cnt0 = 0;
        for (int i = m + 1; i <= m + len; i++) num[s[i] - 'a']--;
        for (int i = L; i <= n / 2; i++) num[s[i] - 'a']++;
        for (int i = 0; i < 26; i++) cnt0 += (num[i] == 0);
        
        int l = L, r = m + len;
        // std::cout << l << ' ' << r << '\n';
        while (cnt0 != 26 && l > 1 && r < n) {
            l--, r++; 
            if (s[l] != s[r]) {
                if (num[s[l] - 'a'] == 0) cnt0--;
                if (num[s[r] - 'a'] == 0) cnt0--;
                if (++num[s[l] - 'a'] == 0) cnt0++;
                if (--num[s[r] - 'a'] == 0) cnt0++;
            }
            ans++;
        }
        while (l > 1 && r < n) {
            l--, r++;
            if (s[l] != s[r]) {
                num[s[l] - 'a']++, num[s[r] - 'a']--; cnt0 = 24;
                ans++;
                while (cnt0 != 26 && l > 1 && r < n) {
                    l--, r++; 
                    if (s[l] != s[r]) {
                        if (num[s[l] - 'a'] == 0) cnt0--;
                        if (num[s[r] - 'a'] == 0) cnt0--;
                        if (++num[s[l] - 'a'] == 0) cnt0++;
                        if (--num[s[r] - 'a'] == 0) cnt0++;
                    }
                    ans++;
                }
            }
        }
        printf("%lld", ans);
    }
    return 0;
}

总结

你说的对, 但是码量真大吧

这个有点吃状态的

posted @ 2025-11-25 15:40  Yorg  阅读(2)  评论(0)    收藏  举报