Loading [MathJax]/extensions/tex2jax.js

Codeforces Round #493 (Div. 1) – 解题报告

A – Convert to Ones

压缩之后算有多少个 \(01\) 对,然后找小的代价乘上再加上取反的代价即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 3e5 + 200;
int n, x, y, cnt;
char str[MAX_N];
int main()
{
scanf("%d%d%d%s", &n, &x, &y, str + 1);
str[0] = '1';
for (int i = 1; i <= n; i++)
cnt += (str[i] == '0' && str[i - 1] == '1');
long long ans = 0;
if (cnt == 0)
ans = 0;
else
ans = 1LL * (cnt - 1) * min(x, y) + y;
printf("%lld\n", ans);
return 0;
}
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 3e5 + 200; int n, x, y, cnt; char str[MAX_N]; int main() { scanf("%d%d%d%s", &n, &x, &y, str + 1); str[0] = '1'; for (int i = 1; i <= n; i++) cnt += (str[i] == '0' && str[i - 1] == '1'); long long ans = 0; if (cnt == 0) ans = 0; else ans = 1LL * (cnt - 1) * min(x, y) + y; printf("%lld\n", ans); return 0; }
// A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 3e5 + 200;

int n, x, y, cnt;
char str[MAX_N];

int main()
{
    scanf("%d%d%d%s", &n, &x, &y, str + 1);
    str[0] = '1';
    for (int i = 1; i <= n; i++)
        cnt += (str[i] == '0' && str[i - 1] == '1');
    long long ans = 0;
    if (cnt == 0)
        ans = 0;
    else
        ans = 1LL * (cnt - 1) * min(x, y) + y;
    printf("%lld\n", ans);
    return 0;
}

B – Roman Digits

打表,发现从 \(11\) 项之后差值恒为 \(49\)。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, series[12] = {0, 4, 10, 20, 35, 56, 83, 116, 155, 198, 244, 292};
int main()
{
int n;
scanf("%d", &n);
if (n <= 11)
printf("%d\n", series[n]);
else
printf("%lld\n", series[11] + 1LL * (n - 11) * 49);
return 0;
}
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200, series[12] = {0, 4, 10, 20, 35, 56, 83, 116, 155, 198, 244, 292}; int main() { int n; scanf("%d", &n); if (n <= 11) printf("%d\n", series[n]); else printf("%lld\n", series[11] + 1LL * (n - 11) * 49); return 0; }
// B.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200, series[12] = {0, 4, 10, 20, 35, 56, 83, 116, 155, 198, 244, 292};

int main()
{
    int n;
    scanf("%d", &n);
    if (n <= 11)
        printf("%d\n", series[n]);
    else
        printf("%lld\n", series[11] + 1LL * (n - 11) * 49);
    return 0;
}

C – Sky Full of Stars

这道题就比较有意思了。

考虑用容斥来算。正常来讲我们算「至少有 \(i\) 行,\(j\) 列」的时候会得到:

\[ {n \choose i} {n \choose j} f(i, j) \]

其中 \(f(i, j)\) 是剩下乱放的方案数。然而,这种计算方式自身就会发生重复,所以我们容斥的时候并不是把「至少转恰好」这一类删掉,而是自身重复的部分、且在不同的 \(i, j\) 时也会重复出现同样多次的部分进行容斥。系数很简单就是一个 \(-1\)。

那么,我们可以开始正常做容斥:

\[ ans = \sum_{i = 0}^n \sum_{j = 0}^n (-1)^{i + j + 1} {n \choose i} {n \choose j} [i + j > 0] f(i, j) \]

考虑 \(f(i, j)\) 的取值。如果 \(i > 0, j > 0\),那么很好得出是 \( 3^{(n – i)(n – j)} \times 3 \)。如果有一维为 \(0\),那么其实选法就变成了 \(3^i 3^{n^2 – ni}\)。带入得到:

\[ ans = \sum_{i = 1}^n \sum_{j = 1}^n (-1)^{i + j + 1} {n \choose i} {n \choose j} 3^{(n – i)(n – j)} + 2\sum_{i = 1}^n (-1)^{i + 1} {n \choose i} 3^i 3^{n^2 – ni} \]

后面那一部分很好用 \(\Theta(n \log n)\) 的时间进行计算,关键是前面那一项,怎么看都是 \(\Theta(n^2)\)。我们把一些东西拆出来、并且分组到最顶级的和式中:

\[ \begin{aligned} part &= \sum_{i = 1}^n \sum_{j = 1}^n (-1)^{i + j + 1} {n \choose i} {n \choose j} 3^{(n – i)(n – j)} \\ &= (-1) \sum_{i = 1}^n (-1)^i {n \choose i} \sum_{j = 1}^n (-1)^j {n \choose j} 3^{n^2 – in – jn + ij} \\ &= (-1) 3^{n^2} \sum_{i = 1}^n (-1)^i {n \choose i} 3^{-in} \sum_{j = 1}^n (-1)^j {n \choose j} 3^{(i – n)j} \end{aligned} \]

后面 \(\sum_{j = 1}^n\) 的部分可以直接二项式合并:

\[ \begin{aligned} part &= (-1) 3^{n^2} \sum_{i = 1}^n (-1)^i {n \choose i} 3^{-in} \sum_{j = 1}^n (-1)^j {n \choose j} 3^{(i – n)j} \\ &= (-1) 3^{n^2} \sum_{i = 1}^n (-1)^i {n \choose i} 3^{-in} [ (1 – 3^{i – n})^n – 1] \end{aligned} \]

搞定了。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, mod = 998244353;
int n, fac[MAX_N], fac_inv[MAX_N], inv[MAX_N];
int fpow(int bas, int tim)
{
int ret = 1;
while (tim)
{
if (tim & 1)
ret = 1LL * ret * bas % mod;
bas = 1LL * bas * bas % mod;
tim >>= 1;
}
return ret;
}
int binomial(int n_, int k_) { return 1LL * fac[n_] * fac_inv[k_] % mod * fac_inv[n_ - k_] % mod; }
int main()
{
scanf("%d", &n);
inv[0] = inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = 1LL * inv[mod % i] * (mod - mod / i) % mod;
for (int i = fac[0] = fac_inv[0] = 1; i <= n; i++)
fac[i] = 1LL * fac[i - 1] * i % mod, fac_inv[i] = 1LL * fac_inv[i - 1] * inv[i] % mod;
int ans = 0;
for (int i = 1, opt = 1; i <= n; i++, opt = mod - opt)
ans = (0LL + ans + 1LL * opt * binomial(n, i) % mod * fpow(3, i) % mod * fpow(3, 1LL * n * (n - i) % (mod - 1)) % mod) % mod;
ans = 2LL * ans % mod;
int part = 0;
for (int i = 1, opt = mod - 1; i <= n; i++, opt = mod - opt)
{
int tmpi = 1LL * opt * binomial(n, i) % mod * fpow(3, ((mod - 1) - 1LL * n * i % (mod - 1)) % (mod - 1)) % mod;
int tmpj = (0LL + fpow((1 + mod - fpow(3, (i + mod - 1 - n) % (mod - 1))) % mod, n) + mod - 1) % mod;
part = (0LL + part + 1LL * tmpi * tmpj % mod) % mod;
}
part = 1LL * part * 3LL % mod * fpow(3, 1LL * n * n % (mod - 1)) % mod * (mod - 1) % mod;
printf("%lld\n", (0LL + part + ans) % mod);
return 0;
}
// C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e6 + 200, mod = 998244353; int n, fac[MAX_N], fac_inv[MAX_N], inv[MAX_N]; int fpow(int bas, int tim) { int ret = 1; while (tim) { if (tim & 1) ret = 1LL * ret * bas % mod; bas = 1LL * bas * bas % mod; tim >>= 1; } return ret; } int binomial(int n_, int k_) { return 1LL * fac[n_] * fac_inv[k_] % mod * fac_inv[n_ - k_] % mod; } int main() { scanf("%d", &n); inv[0] = inv[1] = 1; for (int i = 2; i <= n; i++) inv[i] = 1LL * inv[mod % i] * (mod - mod / i) % mod; for (int i = fac[0] = fac_inv[0] = 1; i <= n; i++) fac[i] = 1LL * fac[i - 1] * i % mod, fac_inv[i] = 1LL * fac_inv[i - 1] * inv[i] % mod; int ans = 0; for (int i = 1, opt = 1; i <= n; i++, opt = mod - opt) ans = (0LL + ans + 1LL * opt * binomial(n, i) % mod * fpow(3, i) % mod * fpow(3, 1LL * n * (n - i) % (mod - 1)) % mod) % mod; ans = 2LL * ans % mod; int part = 0; for (int i = 1, opt = mod - 1; i <= n; i++, opt = mod - opt) { int tmpi = 1LL * opt * binomial(n, i) % mod * fpow(3, ((mod - 1) - 1LL * n * i % (mod - 1)) % (mod - 1)) % mod; int tmpj = (0LL + fpow((1 + mod - fpow(3, (i + mod - 1 - n) % (mod - 1))) % mod, n) + mod - 1) % mod; part = (0LL + part + 1LL * tmpi * tmpj % mod) % mod; } part = 1LL * part * 3LL % mod * fpow(3, 1LL * n * n % (mod - 1)) % mod * (mod - 1) % mod; printf("%lld\n", (0LL + part + ans) % mod); return 0; }
// C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200, mod = 998244353;

int n, fac[MAX_N], fac_inv[MAX_N], inv[MAX_N];

int fpow(int bas, int tim)
{
    int ret = 1;
    while (tim)
    {
        if (tim & 1)
            ret = 1LL * ret * bas % mod;
        bas = 1LL * bas * bas % mod;
        tim >>= 1;
    }
    return ret;
}

int binomial(int n_, int k_) { return 1LL * fac[n_] * fac_inv[k_] % mod * fac_inv[n_ - k_] % mod; }

int main()
{
    scanf("%d", &n);
    inv[0] = inv[1] = 1;
    for (int i = 2; i <= n; i++)
        inv[i] = 1LL * inv[mod % i] * (mod - mod / i) % mod;
    for (int i = fac[0] = fac_inv[0] = 1; i <= n; i++)
        fac[i] = 1LL * fac[i - 1] * i % mod, fac_inv[i] = 1LL * fac_inv[i - 1] * inv[i] % mod;
    int ans = 0;
    for (int i = 1, opt = 1; i <= n; i++, opt = mod - opt)
        ans = (0LL + ans + 1LL * opt * binomial(n, i) % mod * fpow(3, i) % mod * fpow(3, 1LL * n * (n - i) % (mod - 1)) % mod) % mod;
    ans = 2LL * ans % mod;
    int part = 0;
    for (int i = 1, opt = mod - 1; i <= n; i++, opt = mod - opt)
    {
        int tmpi = 1LL * opt * binomial(n, i) % mod * fpow(3, ((mod - 1) - 1LL * n * i % (mod - 1)) % (mod - 1)) % mod;
        int tmpj = (0LL + fpow((1 + mod - fpow(3, (i + mod - 1 - n) % (mod - 1))) % mod, n) + mod - 1) % mod;
        part = (0LL + part + 1LL * tmpi * tmpj % mod) % mod;
    }
    part = 1LL * part * 3LL % mod * fpow(3, 1LL * n * n % (mod - 1)) % mod * (mod - 1) % mod;
    printf("%lld\n", (0LL + part + ans) % mod);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *