Codeforces Round 970 (Div. 3) A~F

A.Sakurako’s Exam (思维)

题意:

SakurakoSakurakoSakurako有一场数学考试。老师给了一个数组,由 aaa个 1 和 bbb个 2 组成。

在数组中,SakurakoSakurakoSakurako必须在每个元素前面放置一个 +-,以使数组中所有元素的总和等于 000

SakurakoSakurakoSakurako不确定是否有可能解决这个问题,因此确定是否有办法分配符号,使得数组中所有元素的总和等于 000

分析:

a,ba,ba,b都为偶数时候,一定可以使得和为000。只需要对半符号相反即可。当aaa为偶数,bbb可以是奇数也可以是偶数。例如1 1 2符合条件,1 1 2 2也符合条件。当aaa是奇数个时,不满足题意。当a,ba,ba,b其中一个为000时,另外一个要为偶数个。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 998244353;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int a, b;
        cin >> a >> b;
        if (a == 0)
        {
            if (b % 2)
                cout << "NO" << endl;
            else
                cout << "YES" << endl;
        }
        else if (b == 0)
        {
            if (a % 2)
                cout << "NO" << endl;
            else
                cout << "YES" << endl;
        }
        else if (a % 2)
            cout << "NO" << endl;
        else
            cout << "YES" << endl;
    }
    return 0;
}

B.Square or Not (思维)

题意:

精美的二进制矩阵是边缘为111而内部为000的矩阵。 SakurakoSakurakoSakurako有一个大小为 r×cr \times cr×c的精美二进制矩阵,并通过写下矩阵的所有行(从第一行开始到第 rrr行结束)创建了一个二进制字符串 sss。换句话说,矩阵中第 iii行和 jjj列的元素对应于字符串的第 ((i−1)∗c+j)((i-1)*c+j)((i1)c+j)个元素。 现在你需要检查字符串 sss所构造的矩阵是不是正方形。

分析:

首先考虑读入的字符串长度是否能构造成正方形,其次因为矩阵的外围为111,中间为000,遍历到 时(i,j)(i,j)(i,j),看字符串对应位置i×n+ji \times \sqrt{n} + ji×n+j的字符是否为对应字符即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 998244353;
void solve()
{
    int n;
    string s;
    cin >> n >> s;
    int m = sqrt(n);
    if (m * m != n)
    {
        cout << "No" << endl;
        return;
    }
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < m; j++)
        {
            char c = '0';
            if (!i || !j || i == m - 1 || j == m - 1)
                c = '1';
            if (s[i * m + j] != c)
            {
                cout << "No" << endl;
                return;
            }
        }
    }
    cout << "Yes" << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C. Longest Good Array (贪心)

题意:

SakurakoSakurakoSakurako正在研究数组。长度为 nnn的数组 aaa被认为是好的,当且仅当:

  • 数组 aaa是递增的,并且对于所有 2≤i≤n2 \le i \le n2in都是 a_i−1<a_ia\_{i - 1} < a\_ia_i1<a_i

  • 相邻元素之间的差异是递增的,意味着对于所有 2≤i<n2 \le i < n2i<n都是 a_i−a_i−1<a_i+1−a_ia\_i - a\_{i-1} < a\_{i+1} - a\_ia_ia_i1<a_i+1a_i

SakurakoSakurakoSakurako已经确定了 lllrrr,并希望构造一个长度最大的好数组,其中对于所有 a_ia\_ia_i都是 l≤a_i≤rl \le a\_i \le rla_ir

帮助 SakurakoSakurakoSakurako找到给定 lllrrr的好数组的最大长度。

分析:

我们贪心的考虑这个问题,让差值每次递增111,例如l,l+1,l+3,l+6l,l+1,l+3,l+6l,l+1,l+3,l+6这样进行构造,再二分答案能构造的最大长度即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 998244353;
void solve()
{
    LL L, R;
    cin >> L >> R;
    LL l = 0, r = R;
    while (l < r)
    {
        LL mid = l + r + 1 >> 1;
        LL sum = (1 + mid) * mid / 2;
        if (L + sum <= R)
            l = mid;
        else
            r = mid - 1;
    }
    cout << r + 1 << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

D. Sakurako’s Hobby (枚举)

题意:

对于某个排列 pppSakurakoSakurakoSakurako规定整数 jjj可以通过 iii到达,当且仅当可以通过进行若干次 i=p_ii=p\_ii=p_i的操作 ,使 iii等于 jjj

如果是 p=[3,5,6,1,2,4]p=[3,5,6,1,2,4]p=[3,5,6,1,2,4],那么例如, 444可以从 111到达,因为: i=1i=1i=1→\rightarrowi=p_1=3i=p\_1=3i=p_1=3→\rightarrowi=p_3=6i=p\_3=6i=p_3=6→\rightarrowi=p_6=4i=p\_6=4i=p_6=4。现在为 i=4i=4i=4,因此 444可从 111到达。

排列中的每个数字都被涂成黑色或白色。

SakurakoSakurakoSakurako将函数 F(i)F(i)F(i)定义为可从 iii到达的黑色整数的数量。

请计算出每个 1≤i≤n1\le i\le n1inF(i)F(i)F(i)的值。

分析:

考虑到题目给出的是排列,那么所有元素在按照规则遍历时,会出现环状结构(最后到达本身),这个环上的所有元素 F(i)F(i)F(i)都相等。我们逐个循环枚举就可以求出所有的F(i)F(i)F(i)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 998244353;
void solve()
{
    LL n;
    cin >> n;
    LL p[n + 1] = {0}, b[n + 1] = {0};
    int us[n + 1] = {0};
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i];
    }
    string s;
    cin >> s;
    for (int i = 1; i <= n; i++)
    {
        if (us[i])
            continue;
        int sz = 0;
        while (!us[i])
        {
            us[i] = 1;
            sz += s[i - 1] == '0';
            i = p[i];
        }
        while (us[i] != 2)
        {
            b[i] = sz;
            us[i] = 2;
            i = p[i];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cout << b[i] << " ";
    }
    cout << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

E. Alternating String (dp)

题意:

SakurakoSakurakoSakurako非常喜欢交替字符串。如果偶数位置上的字符相同,奇数位置上的字符相同,并且字符串的长度为偶数,她将小写拉丁字母的字符串 sss称为交替字符串。

例如,字符串 ababgg 是交替的,而字符串 abaggwp 则不是。

现在,你可以对字符串执行两种类型的操作:

  1. 选择一个索引 iii,并从字符串中删除第 iii个字符,这将使字符串的长度减少 111。这种类型的操作最多只能执行 111次;

  2. 选择索引 iii,并将 s_is\_is_i替换为任何其他字母。

给出使字符串变为交替字符串所需的最少操作数。

分析:

因为只能删除一次字符,所以长度为奇数时才考虑删除。我们令num[i][j]num[i][j]num[i][j]表示奇数位或者偶数位,各种字符出现的次数。当nnn为偶数时,分别找到奇数位与偶数位出现最多字符的次数,这些字符保持不变。那么有ans=n−max(num_0,num_0+25)−max(num_1,num_1+25);ans=n-max(num\_0,num\_0+25)-max(num\_1,num\_1+25);ans=nmax(num_0,num_0+25)max(num_1,num_1+25);。当nnn为奇数时,我们只要遍历1−n1-n1n,表示删除该字符后的操作次数,最终去最小值即可。 我们再令tmp[i][j]tmp[i][j]tmp[i][j]表示在当前位置上各个字符出现的次数,再令cnt[i][j]cnt[i][j]cnt[i][j]表示删除该位置上字符后整个字符串上奇偶字符数。那么有cnt[0][j]=tmp[0][j]+num[1][j]−tmp[1][j]cnt[0][j]=tmp[0][j]+num[1][j]-tmp[1][j]cnt[0][j]=tmp[0][j]+num[1][j]tmp[1][j]cnt[1][j]=tmp[1][j]+num[0][j]−tmp[0][j]cnt[1][j]=tmp[1][j]+num[0][j]-tmp[0][j]cnt[1][j]=tmp[1][j]+num[0][j]tmp[0][j]

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 998244353;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        string s;
        cin >> s;
        int ans = n;
        int cnt[2][26]{};
        for (int i = 0; i < n; i++)
        {
            cnt[i % 2][s[i] - 'a']++;
        }
        if (n % 2 == 0)
        {
            ans = ans - *max_element(cnt[0], cnt[0] + 26) - *max_element(cnt[1], cnt[1] + 26);
        }
        for (int i = n - 1; i >= 0; i--)
        {
            cnt[i % 2][s[i] - 'a']--;
            if (n % 2)
            {
                ans = min(ans, n - *max_element(cnt[0], cnt[0] + 26) - *max_element(cnt[1], cnt[1] + 26));
            }
            cnt[(i + 1) % 2][s[i] - 'a']++;
        }
        cout << ans << endl;
    }
    return 0;
}

F. Sakurako’s Box (数学)

题意:

SakurakoSakurakoSakurako有一个装有 nnn个球的盒子。每个球都有其价值。她想和朋友打赌,朋友能否从盒子中随机挑选两个球(可能是两个不同的球,但它们的价值可能相同),它们的价值乘积将与 SakurakoSakurakoSakurako猜测的数字相同。 现在你要帮他找出数组中两个元素乘积的期望值。 可以证明期望值的形式为 PQ\frac{P}{Q}QP,其中 PPPQQQ为非负整数,并且为 Q≠0Q \ne 0Q=0。输出 P⋅Q−1( mod 109+7)P \cdot Q^{-1}(\bmod 10^9+7)PQ1(mod109+7)的值。

分析:

数组中数对的数量为C_n2=n∗(n−1)2C\_n^2 = \frac{n*(n-1)}{2}C_n2=2n(n1),所有数对的乘积和为sum=∑_i=2n∑_j=1i−1a_j∗a_isum = \sum\_{i=2}^n \sum\_{j=1}^{i-1}a\_j*a\_isum=_i=2n_j=1i1a_ja_i,那么期望值就是sumC2_n\frac{sum}{C^2\_{n}}C2_nsum。我们再用前缀和进行优化,令f(i)=∑_j=1ia_if(i) = \sum\_{j=1}^i a\_if(i)=_j=1ia_isum=∑_i=2na_i∗∑_j=1i−1a_j=∑_i=2na_i∗f(i−1)sum=\sum\_{i=2}^n a\_i *\sum\_{j=1}^{i-1}a\_j = \sum\_{i=2}^n a\_i * f(i-1)sum=_i=2na_i_j=1i1a_j=_i=2na_if(i1)。再用快速幂算出逆元进行计算即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
#define PII pair<LL, LL>
const int N = 3e5 + 10;
const int InF = 2e9 + 5;
const int mod = 1e9 + 7;
LL qmi(LL a, int b)
{
    LL res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        LL n;
        cin >> n;
        LL pre = 0, sum = 0;
        for (int i = 1; i <= n; i++)
        {
            LL x;
            cin >> x;
            if (i > 1)
            {
                (sum += pre * x % mod) %= mod;
            }
            (pre += x) %= mod;
        }
        LL ans = sum * qmi(n * (n - 1) % mod * qmi(2, mod - 2) % mod, mod - 2) % mod;
        cout << ans << endl;
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值