跳转至

CSP模拟赛四

T1

知识点:循环

参考代码
int ans = x;
while (x != 0)
{
    ans += x / y * 2;
    x /= y;
}   
cout << ans;

T2

知识点:循环,闰年判断

参考代码
bool leap(int y)
{
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
int ans = 0;
for (int i = l; i <= r; i++)
{
    if (leap(i))
    {
        ans += 366;
    }
}

T3

知识点:字符串,转义字符。

核心思路:构造出正确的输入输出字符串,然后和输入给出的进行比较即可。

参考代码
string in = "freopen(\"" + s + ".in\",\"r\",stdin);";
string out = "freopen(\"" + s + ".out\",\"w\",stdout);";
if (in == a && out == b)
    cout << "Yes";
else
    cout << "No";

T4

知识点:数学

思路:求出恰好大于等于 $n$ 的超级奇数,然后减去 $n$ 即可。

枚举 $n$ 往后的所有整数,一一判断显然会 TLE。可以通过构造的方式找到超级奇数。

  • 从高位开始找到第一个是偶数的数位,记作是 $i$。
  • 第 $i$ 位以前,原封不动。
  • 第 $i$ 位的值加 $1$ 变为奇数。
  • 第 $i$ 位以后,全部变为 $1$。

如此构造即可得到恰好大于等于 $n$ 的超级奇数。时间复杂度相当于遍历一次 $n$ 的所有数位。

参考代码
long long solve(long long n)
{
    string s = to_string(n);
    for (int i = 0; i < s.size(); i++)
    {
        int x = s[i] - '0';
        if (x % 2 == 0)
        {
            s[i] += 1;
            for (int j = i + 1; j < s.size(); j++)
            {
                s[j] = '1';
            }
            break;
        }
    }
    return stoll(s);
}

T5

知识点:和式化简,前缀和。

定义 $s_i=\sum\limits_{j=1}^i a_j$,则 $a_i+\ldots + a_j=s_j-s_{i-1}$。

那么

\[ \begin{aligned} ans &= \sum\limits_{i=l}^r \sum\limits_{j=i}^r (a_i+a_{i+1}+\ldots+a_j)\\ &=\sum\limits_{i=l}^r \sum\limits_{j=i}^r (s_{j}-s_{i-1}) \end{aligned} \]

首先利用和式的可拆分性质可以得到

\[ \begin{aligned} ans &=\sum\limits_{i=l}^r \sum\limits_{j=i}^r s_{j}-\sum\limits_{i=l}^r \sum\limits_{j=i}^r s_{i-1}. \end{aligned} \]

不难看出 $\sum\limits_{j=i}^r s_{j}$ 可以用前缀和的前缀和表示。因此定义

  • $S_1[i]=\sum\limits_{j=1}^i s_j$。

\[ \sum\limits_{j=i}^r s_{j}=S_1[r]-S_1[i-1]. \]

那么第一部分就变为

\[ \sum\limits_{i=l}^r\big(S_1[r]-S_1[i-1]\big) = S_1[r]\times (r-l+1)\;-\;\sum\limits_{i=l}^r S_1[i-1]. \]

把 $\sum\limits_{i=l}^r S_1[i-1]$ 也写成前缀和的前缀和。定义

  • $S_2[i]=\sum\limits_{j=1}^i S_1[j]$,

\[ \sum\limits_{i=l}^r S_1[i-1]=\sum\limits_{t=l-1}^{r-1} S_1[t]=S_2[r-1]-S_2[l-2]. \]

于是第一部分为

\[ \boxed{\;\sum\limits_{i=l}^r \sum\limits_{j=i}^r s_{j} = S_1[r]\,(r-l+1)\;-\;\big(S_2[r-1]-S_2[l-2]\big)\;} \]

同理得到

\[ \begin{aligned} \sum\limits_{i=l}^r \sum\limits_{j=i}^r s_{i-1} &= \sum\limits_{i=l}^r s_{i-1}\cdot (r-i+1)\\ &= r\cdot \sum\limits_{i=l}^r s_{i-1}-\sum\limits_{i=l}^r (i-1)\,s_{i-1}. \end{aligned} \]

注意这里

\[ \sum\limits_{i=l}^r s_{i-1}=\sum\limits_{t=l-1}^{r-1} s_t = S_1[r-1]-S_1[l-2], \]

而 $\sum\limits_{i=l}^r (i-1)\,s_{i-1}=\sum\limits_{t=l-1}^{r-1} t\,s_t$ 需要“带权”的前缀和。定义

  • $S_3[i]=\sum\limits_{j=1}^i j\cdot s_j$,

\[ \sum\limits_{i=l}^r (i-1)\,s_{i-1}=S_3[r-1]-S_3[l-2]. \]

于是第二部分为

\[ \boxed{\;\sum\limits_{i=l}^r \sum\limits_{j=i}^r s_{i-1} = r\cdot \big(S_1[r-1]-S_1[l-2]\big)\;-\;\big(S_3[r-1]-S_3[l-2]\big)\;} \]

总结:

\[ \boxed{ \begin{aligned} ans &=\Big[S_1[r]\,(r-l+1)\;-\;\big(S_2[r-1]-S_2[l-2]\big)\Big]\\ &\quad-\Big[r\cdot \big(S_1[r-1]-S_1[l-2]\big)\;-\;\big(S_3[r-1]-S_3[l-2]\big)\Big]\\ &=S_1[r]\,(r-l+1)\;-\;\big(S_2[r-1]-S_2[l-2]\big)\;-\;r\big(S_1[r-1]-S_1[l-2]\big)\;+\;\big(S_3[r-1]-S_3[l-2]\big). \end{aligned}} \]

其中

  • $s_i=a_1+a_{2}+\ldots+a_i$
  • $S_1[i]=\sum\limits_{j=1}^i s_j$
  • $S_2[i]=\sum\limits_{j=1}^i S_1[j]$
  • $S_3[i]=\sum\limits_{j=1}^i j\cdot s_j$

并约定越界下标($\le 0$)时这些量为 0(如 $S_1[0]=S_2[0]=S_3[0]=0$)。

参考代码
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, q;
    cin >> n >> q;
    vector<int64> a(n + 1), s(n + 1), S1(n + 1), S2(n + 1), S3(n + 1);
    // 输入
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    // 预处理
    for (int i = 1; i <= n; i++)
    {
        s[i] = s[i - 1] + a[i];             // 前缀和
        S1[i] = S1[i - 1] + s[i];           // s 的前缀和
        S2[i] = S2[i - 1] + S1[i];          // S1 的前缀和
        S3[i] = S3[i - 1] + 1LL * i * s[i]; // 带权前缀和
    }
    while (q--)
    {
        int l, r;
        cin >> l >> r;
        // 注意边界:当 l = 1 时 l-2 会是 -1,下标要安全处理
        auto get = [&](const vector<int64> &arr, int idx)
        {
            if (idx < 0)
                return 0LL;
            return arr[idx];
        };
        int64 part1 = S1[r] * (r - l + 1) - (get(S2, r - 1) - get(S2, l - 2));
        int64 part2 = 1LL * r * (get(S1, r - 1) - get(S1, l - 2)) - (get(S3, r - 1) - get(S3, l - 2));
        int64 ans = part1 - part2;
        cout << ans << "\n";
    }
    return 0;
}

T6

知识点:拆点 BFS

参考代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using pii = pair<int, int>;
template <typename T>
using vec = vector<T>;
constexpr int N = 2e5 + 5, mod = 998244353;

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    int n, m;
    cin >> n >> m;
    vec<vec<char>> a(n + 1, vec<char>(m + 1));
    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
            if (a[i][j] == 'S')
            {
                x1 = i, y1 = j;
            }
            if (a[i][j] == 'E')
            {
                x2 = i, y2 = j;
            }
        }
    }


    const int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
    vec<vec<vec<vec<int>>>> dis(n + 1, vec<vec<vec<int>>>(m + 1, vec<vec<int>>(4, vec<int>(4, 1e9))));
    queue<array<int, 4>> q;
    for (int i = 0; i < 4; i++)
    {
        dis[x1][y1][i][1] = 0;
        q.push({x1, y1, i, 1});
    }

    while (!q.empty())
    {
        auto [x, y, fx, d] = q.front();
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dx[i], ny = y + dy[i];
            if (nx < 1 || nx > n || ny < 1 || ny > m || a[nx][ny] == '#')
                continue;
            if (i == fx)
            {
                if (d < 3)
                {
                    if (dis[nx][ny][i][d + 1] == 1e9)
                    {
                        dis[nx][ny][i][d + 1] = dis[x][y][fx][d] + 1;
                        q.push({nx, ny, i, d + 1});
                    }
                }
            }
            else
            {
                if (dis[nx][ny][i][1] == 1e9)
                {
                    dis[nx][ny][i][1] = dis[x][y][fx][d] + 1;
                    q.push({nx, ny, i, 1});
                }
            }
        }
    }
    int ans = 1e9;
    for (int i = 0; i < 4; i++)
        for (int j = 1; j <= 3; j++)
            ans = min(ans, dis[x2][y2][i][j]);
    if (ans == 1e9) ans = -1;
    cout << ans;
    return 0;
}

T7

知识点:差分,前缀和。

参考代码
while (m--)
{
    int l, r;
    cin >> l >> r;
    int len = r - l + 1;
    a[l] += 1;
    if (l + 1 <= n)
        a[l + 1] += 1;
    if (r + 1 <= n)
        a[r + 1] += -Z(len + 1) * (len + 1);
    if (r + 2 <= n)
        a[r + 2] += Z(2) * len * len + 2 * len - 1;
    if (r + 3 <= n)
        a[r + 3] += -Z(len) * len;
}   
for (int i = 1; i <= n; i++)
    a[i] += a[i - 1];
for (int i = 1; i <= n; i++)
    a[i] += a[i - 1];
for (int i = 1; i <= n; i++)
    a[i] += a[i - 1];
for (int i = 1; i <= n; i++)
    cout << a[i] << " ";