1931(925div3)

A. Recovering a Small String

az126 给出 3 个字母的和,求字典序最小的 3 个字母

void solve() {
    int n;cin >> n;
    for (int i = 'a';i <= 'z';i++) {
        for (int j = 'a';j <= 'z';j++) {
            for (int k = 'a';k <= 'z';k++) {
                if (i + j + k - 'a' * 3 + 3 == n) {
                    cout << char(i) << char(j) << char(k) << '\n';return;
                }
            }
        }
    }
}

B. Make Equal

给出一个数组,其之和一定是 n 的倍数,可选择 i,j(i<j)ai=x,aj+=x ,问是否存在每个数都相等的情况

void solve() {
    int n, sum = 0; cin >> n;
    vector<int> a(n);
    for (auto& i : a)cin >> i, sum += i;
    int eq = sum / n,cnt = 0;
    bool ok = true;
    for (int i = 0;i < n;i++) {
        if (a[i] >= eq) {
            cnt += a[i] - eq;
        } else {
            cnt -= eq - a[i];
            if (cnt < 0)ok = false;
        }
    }
    if (ok) {
        cout << "yes\n";
    } else {
        cout << "no\n";
    }
}

C. Make Equal Again

只能执行一次操作,给定区间加上任意值,求最少的区间长度

就看两边的就行

void solve() {
    int n;cin >> n;vector<int> a(n);
    for (auto& i : a)cin >> i;
    int cnt1 = 1, cnt2 = 1;
    for (int i = 1;i < n;i++) {
        if (a[i] == a[i - 1]) {
            cnt1++;
        } else break;
    }
    for (int i = n - 1;i >= 0;i--) {
        if (a[i] == a[i - 1]) {
            cnt2++;
        } else break;
    }
    if (cnt1 == cnt2 && cnt1 == n) {
        cout << 0 << '\n';return;
    }
    if (a[0] == a[n - 1]) {
        cout << n - (cnt1 + cnt2) << '\n';
    } else {
        cout << n - max(cnt1, cnt2) << '\n';
    }
}

D. Divisible Pairs

给出一个数组 a,求满足 (ai+aj)%x=0(aiaj)%y=0(i<j) 的个数。

Solution

易得:

(ai%x+aj%x)%x=0,(ai%yaj%y)%y=0
ai%x+aj%x=x,ai%yaj%y=0

存下 ai%x,ai%y,满足 (xai%x)%xai%y 即为对应的条件

void solve() {
    int n, x, y;cin >> n >> x >> y;
    vector<int> a(n);
    for (auto& i : a)cin >> i;
    ll cnt = 0;
    map<pair<int, int>, int> mod;
    for (int i = 0;i < n;i++) {
        cnt += mod[{(x - a[i] % x) % x, a[i] % y}];
        mod[{a[i] % x, a[i] % y}]++;
    }
    cout << cnt << '\n';
}

void solve() {
    int n, x, y;cin >> n >> x >> y;
    vector<int> a(n);
    for (auto& i : a)cin >> i;
    ll cnt = 0;
    map<pair<int, int>, int> mod;
    for (int i = 0;i < n;i++) {
        mod[{a[i] % x, a[i] % y}]++;
    }
    for (int i = 0;i < n;i++) {
        --mod[{a[i] % x, a[i] % y}];
        cnt += mod[{(x - a[i] % x) % x, a[i] % y}];
        ++mod[{a[i] % x, a[i] % y}];
    }
    cout << cnt / 2 << '\n';
}

E. Anna and the Valentine's Day Gift

给出一个长度为 n 的数组 a,Anna 先手

当 Anna 下完棋且数组中只剩下一个元素的时候,游戏结束,如果剩下的数字 10m,Sasha 获胜,反之,Anna 获胜。

双方都以最佳方式玩游戏,输出获胜方。

Solution

博弈论

容易发现,Anna 每次优先翻转 后导 0 最多的数,Sasha 每次优先以 有最多后导 0 的数 作为 ai

a={10,10,10,10}.m=5 为例执行流程:

即每次 Anna 删除一个最多的,Sasha 保留一个第二多的,以此类推。

比较简单。

void solve() {
    int n, m;cin >> n >> m;
    vector<pair<int, int>> a(n);for (auto& [i, j] : a)cin >> j;
    int sum = 0;
    for (int i = 0;i < n;i++) {
        string num = to_string(a[i].second);
        sum += num.size();
        int cnt = 0;
        for (int i = num.size() - 1;i >= 0;i--) {
            if (num[i] == '0')cnt++;
            else break;
        }
        a[i].first = cnt;
    }
    sort(a.begin(), a.end());
    for (int i = n - 1;i >= 0;i -= 2) {
        sum -= a[i].first;
    }
    if (sum - 1 >= m)cout << "Sasha\n";
    else cout << "Anna\n";
}

F. Chat Screenshots

编程竞赛聊天室有 n 人。聊天参与者按活动排序,但每个人都把自己排在最前面。

例如,有 4 人参加聊天,他们的顺序是 [2,3,1,4] 。那么

k 人在聊天中发布了截图,显示了该用户看到的参与者顺序。这些截图是在很短的时间内截取的,参与者的顺序并没有改变。

你的任务是确定所有截图是否都有一定的顺序。

Solution

拓扑排序

按照题意:每个人截图后的 2n 的相对顺序是一定的。所以只需要将每个人的 2n 的相对顺序建图,如果没有出现环则一定存在,有环则出现矛盾,一定不存在。

void solve() {
    int n, k;cin >> n >> k;
    vector<int> g[n + 1], du(n + 1, 0);
    for (int i = 0;i < k;i++) {
        vector<int> a(n);
        for (int j = 0;j < n;j++) {
            cin >> a[j];
        }
        for (int j = 1;j < n - 1;j++) {
            g[a[j]].push_back(a[j + 1]);
            du[a[j + 1]]++;
        }
    }

    queue<int> q;
    for (int i = 1;i <= n;i++) {
        if (!du[i])q.push(i);
    }
    while (q.size()) {
        int t = q.front();q.pop();
        for (auto i : g[t])
            if (!--du[i])q.push(i);
    }
    for (int i = 1;i <= n;i++) {
        if (du[i]) {
            cout << "NO\n";return;
        }
    }
    cout << "YES\n";
}

G. One-Dimensional Puzzle

每种类型包含 a,b,c,d 个元素。如果成功地将所有元素组合成一条长链,就算完成了。求有多少种方法(不能翻转)。

Solution

组合数 (隔板法)

Codeforces Round 925 (Div. 3) A-G 比赛录屏+讲解(60分钟开始)_哔哩哔哩_bilibili

注意:本题写的 C(x,y) 写为了 C(y,x) (写反了 )

前置小练习:

eg1: 将 10 个相同的小球放入 8 个盒子里(每个盒子至少有一个小球),有多少种放法?

插空法:10 个小球有 9 个空可以插,有 7 个隔板, (即两块板之间不能相邻且第一块板左侧与最后一块板右侧必须有球)。

则答案 C(7,9)

eg2: 将 10 个相同的小球放入 8 个盒子里 (盒子可以为空),有多少种放法?

隔板法:10 个小球和 7 个隔板,可以组成一个由 17 个物件的排列,从中选择 7 个位置放置隔板,这样就可以把小球分配到 8 个盒子中

答案:C(7,17)

eg3:x1+x2+x3+x4=10 有多少个正整数解?

即在 1,1,1,,1(101) 中选择 3 个空插入,答案:C(3,9)

eg4:x1+x2+x3+x4=10 有多少个非负整数解?

法一:可以变换一下思路:这时的 xi0,将等式两边同时加上 4,则 xi1x1+x2+x3+x4=14 的正整数解

法二:将 3 个隔板和 10 组成一个 13 件物品的排列,选择 3 个位置放置隔板

答案:C(3,13)

则可以抽象:

x1+x2+x3++xr=n 的非负整数解个数以及正整数解个数。

(1): C(r1,r+n1)

(2):C(r1,n1)

n 个相同的小球放入 r 个盒子里, (盒子可以为空和至少一个)各有多少种放法?

(1):C(r1,n+r1)

(2):C(r1,n1)

可以在 1,2 之间插入 3,在 2,1 之间插入 4

本题目插入的意思 ,设空位个数为 m

  1. c|d3|4 放到 m 个空位空位中 (可以为空)的方法个数
  2. x1+x2+x3++xm=c|d 非负整数解个数

下面的个数为 C(m1,m+c|d1),由于插入 3|4 不冲突,所以直接相乘。

a=b

方案数:C(a1,a+c1)×C(a,a+d)+C(a,a+c)×C(a1,a+d1)

a=b1

方案数:C(a,a+c)×C(a,a+d)

a=b+1

方案数:C(a1,a+c1)×C(a1,a+d1)

然后就是预处理与逆元(本处为线性递推,快速幂也可)的计算。(待更 )

const int mod = 998244353, N = 2e6 + 10;
ll fac[N], jv[N], inv[N];
void init(int n) {
    jv[0] = fac[0] = 1;
    for (int i = 1;i <= n;i++) {
        inv[i] = i == 1 ? 1 : (mod - mod / i) * inv[mod % i] % mod;
        fac[i] = fac[i - 1] * i % mod;
        jv[i] = jv[i - 1] * inv[i] % mod;
    }
}
ll C(int m, int n) {
    if (n < m || m < 0) return 0;
    return fac[n] * jv[n - m] % mod * jv[m] % mod;
}
void solve() {
    int a, b, c, d;cin >> a >> b >> c >> d;
    if (abs(a - b) >= 2) {
        cout << 0 << '\n';return;
    }
    ll ans = 0;
    if (!a && !b)ans = c == 0 || d == 0;
    else if (a == b) {
        ans = (C(a - 1, a + c - 1) * C(a, a + d) % mod + C(a, a + c) * C(a - 1, a + d - 1) % mod) % mod;
    } else if (a == b - 1) {
        ans = C(a, a + c) * C(a, a + d) % mod;
    } else if (a == b + 1) {
        ans = C(a - 1, a + c - 1) * C(a - 1, a + d - 1) % mod;
    }
    cout << ans << '\n';
}
main::init(2e6);