2021杭電多校第零場 & 2021湘潭全國邀請賽 補題記錄


比賽鏈接:Here

本場題目重現於 2021湘潭全國邀請賽

A - A+B Problem (簽到)

根據題意處理即可

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int _; for (cin >> _; _--;) {
        int a, b;
        cin >> a >> b;
        if (a + b <= 1023 and a + b >= -1024)cout << a + b << "\n";
        else if (a + b > 1023)cout << a + b - 2048 << "\n";
        else cout << a + b + 2048 << "\n";
    }
}

B - Binary Number

C - Calculate

D - Car

E - CCPC Strings (math)

思路來自 聆竹聽風

題意:長度為 \(n\) 的只含有”C”或”P”的字符串共有 (\(2^n\))個,問:這所有(\(2^n\))個字符串中含有多少個”CCPC”(每一個”CCPC”之間不能相互重疊,即”CCPCCPC”中只能算(1)個”CCPC”)


假設所有長度為(\(n\))的”CP”字符串中互不重疊的”CCPC”的個數為(\(a_n\))

若認為可以相互重疊,可以通過計算貢獻的方式進行計算

詳細見 Here

const int mod = 1e9 + 7;
ll a[10];
ll qpow(ll a, ll b) {
    ll ans = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1) ans = (ans * a) % mod;
    return ans;
}
ll cal(ll x) {
    ll an = qpow(2, x - 1) * 64 % mod, a1 = qpow(2, (x - 1) % 6 + 6);
    ll inv63 = qpow(63, mod - 2);
    ll c = x % 6, z = (x - 1) % 6;
    if (c == 0) c += 6;
    ll s1 = c * qpow(2, z) % mod;
    return ((x * qpow(2, x + 5) % mod - 6 * (an - a1 + mod) % mod * inv63 % mod + mod) % mod - s1) % mod * inv63 % mod;
}

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    a[4] = 1, a[5] = 4, a[6] = 12;
    int _; for (cin >> _; _--;) {
        ll n; cin >> n;
        if (n < 7) cout << a[n] << "\n";
        else cout << (cal(n - 3) - cal(n - 6) + mod ) % mod << '\n';
    }
}

F - Control in a Matrix

G - Game (思維)

首先分析x−(10k−1),減的這個數只能是9,99,999,…

99=9 * 11
999=9 * 111
999…=9 * K

這些數都是9的倍數,K是個奇數,所以對結果沒有影響,因此我們可以將這個問題轉化為每次減9

將這些數從小到大排序,每次先從最小的開始減

例如:19 10 29 不排序從第一個開始減最后減到的最小結果就是19 10 11(因為19-9=10,與第二個數字10有重復)
排序后的最小結果是1 10 11,這個在計算過程中不會出現少操作數,每個人都可以做到最佳選擇

因為存在最后減完的結果一樣,但是題目要求不可以出現重復的數字,所以需要再次處理
每次從最小的開始減,余數不為0的每次就讓第一個減到0*9+余數,第二個減到1 * 9+余數…以此類推(如果余數為0,第一個減到1 * 9,第二個減到2 * 9,以此類推)

這里的避重(避免重復)操作數可以用前n項和實現
(余數為0) 例:9 18 27 化為最小結果(未對余數進行避重)分別需要的操作是 1 2 3次,總操作數=6
避重的話9應該減為1 * 9,18減為2 * 9,27減為3 * 9,需要的總操作數是1+2+3=6次
6-6=0,所以最后只能對這組數據進行0次操作。
(余數不為0),與上類似,只是第一個數減到0 * 9+余數…

最后總結我們需要計算的就是:

一、將每個數化到最小一共需要多少次操作(一共能減多少次9,先不考慮余數相同)
二、統計余數相同的個數(對9取余 余數為0到8)
三、余數相同的數字,計算去重操作數
四、總操作數-避重操作數即為最后的操作數,如果為偶數,則B贏,反之,則A贏。

const int N = 1e6 + 10;
ll a[N], book[100]; // book 不要取太大,memset太花時間
int n;
int main() {
    //cin.tie(nullptr)->sync_with_stdio(false);
    while (~scanf("%d", &n) and n) {
        memset(book, 0, sizeof(book));
        for (int i = 0; i < n; ++i) scanf("%d", a + i);
        sort(a, a + n);
        int sum = 0;
        for (int i = 0; i < n; ++i) {
            int b = a[i] % 9;
            if (b == 0)b = 9;
            sum += (a[i] - b - book[b] * 9) / 9;
            book[b]++;
        }
        cout << "BA"[sum & 1] << "\n";
    }
}

H - Huge Directed Graph

I - Sequence

J - Stacks (Good)

很巧妙的圖論搜索題,

把棧想成圖中的點,根據操作將設定好的結構體左右端點相連。

最后判斷情況輸出即可

const int N = 1e5 + 10;
struct node {
    int l, r;
} q[N];

int idx, n, m, k;
vector<int>e[N];
int b[N];

void dfs(int u, int f) {
    for (int v : e[u]) {
        if (v == f)continue;
        b[++k] = v;
        dfs(v, u);
    }
}

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    while (cin >> n >> m) {
        idx = 0;
        for (int i = 1; i <= n; ++i) q[i].l = q[i].r = i, e[i].clear();

        while (m--) {
            int a, b;;
            cin >> a >> b;
            if (q[a].l and q[b].l) { // a,b
                e[q[a].l].push_back(q[b].l);
                e[q[b].l].push_back(q[a].l);
                q[b].l = q[a].r;
                q[a].l = q[a].r = 0;
            } else if (q[a].l and !q[b].l) { // a,b
                q[b].l = q[a].r;
                q[b].r = q[a].l;
                q[a].l = q[a].r = 0;
            }
        }

        for (int i = 1; i <= n; ++i) {
            if (!q[i].l)cout << "0\n";
            else {
                k = 0;
                dfs(q[i].l, -1);
                cout << k + 1 << " " << q[i].l;
                for (int i = 1; i <= k; ++i) cout << " " << b[i];
                cout << "\n";
            }
        }
    }
}

K - Substring (滑動窗口)

滑動窗口,開一個隊列數組存出現過的字母下標

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    int k; string s;
    while (cin >> k >> s) {
        queue<int>a[26];
        int n = s.length();
        int i = 0, j = 1;
        a[s[0] - 'a'].push(0);
        int Len = 1;
        while (i <= j and j < n) {
            int t = s[j] - 'a';
            a[t].push(j);
            if (a[t].size() <= k)Len = max(Len, j - i + 1);
            else {
                for (int k = i; k < a[t].front(); ++k) a[s[k] - 'a'].pop();
                i = a[t].front() + 1;
                a[t].pop();
            }
            j++;
        }
        cout << Len << '\n';
    }
}

L - Swap


免責聲明!

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



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