Codeforces think cell Round 1 A~E

A.Maximise The Score(贪心)

题意:

白板上写着 2n2n2n 个正整数。你觉得无聊,决定用白板上的数字玩一个单人游戏。

开始时,你的分数为000。你可以通过走下面的棋nnn次来增加你的分数:

  • 选择写在白板上的两个整数xxxyyy
  • min⁡(x,y)\min(x,y)min(x,y)加到您的分数中。
  • 擦去白板上的xxxyyy

注意,在走完nnn步之后,白板上不会有任何整数。

如果你以最佳方式走完nnn步棋,计算你最终能得到的最高分。

分析:

将数组从大到小排序,每次加分为两数中的最小值,能够发现数组中的最大值一定不会作为分数加入,若一次选择最大值与任意数,则可以将任意数加入分数,所以每次选择第二大的值与最大值一起被删除,重复此操作即为最优。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL N = 2e5 + 10;

int a[N];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 0; i < 2 * n; i++) cin >> a[i];
        sort(a, a + 2 * n);
        int ans = 0;
        for (int i = 0; i < n; i++) ans += a[2 * i];
        cout << ans << endl;
    }
    return 0;
}

B.Permutation Printing(模拟)

题意:

给你一个正整数nnn

请找出一个长度为nnn的排列†^\dagger。要求长度为nnn的排列ppp中,不存在两个不同的索引iiijjj1≤i,j<n1\leq i,j \lt n1i,j<ni≠ji\neq ji=j),使得pip_ipi整除pjp_jpjpi+1p_{i+1}pi+1整除pj+1p_{j+1}pj+1。(1≤i,j<n1\leq i,j \lt n1i,j<n;i≠ji\neq ji=j)。

在此问题的限制条件下,可以证明至少存在一个ppp

†^\dagger长度为nnn的排列是由nnn个不同的整数组成的数组,这些整数从111nnn依次排列。例如,[2,3,1,5,4][2,3,1,5,4][2,3,1,5,4]是一个排列,但[1,2,2][1,2,2][1,2,2]不是一个排列(222出现了两次),[1,3,4][1,3,4][1,3,4] 也不是一个排列(n=3n=3n=3,但数组中有444)。

分析:

任意>n2\gt \frac{n}{2}>2n的数字都不可能是任何数字的倍数。若我们大小交替排序,如果aia_iai能够整除aja_jaj,那么一定会有ai+1>aj+1a_{i+1}\gt a_{j+1}ai+1>aj+1,不可能满足整除,交替排序即可。

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int i = 1, j = n;
        while (i < j) {
            cout << i << ' ' << j << ' ';
            i++;
            j--;
        }
        if (i == j)
            cout << i << ' ';
        cout << endl;
    }
    return 0;
}

C.Lexicographically Largest(模拟)

题意:

史塔克有一个长度为nnn的数组aaa。他还有一个空集SSS。注意,SSS并不是一个多重集。

他将进行以下三步操作恰好nnn次:

  1. 选择一个序号iii,使得1≤i≤∣a∣1\leq i\leq|a|1ia
  2. †^\daggerai+ia_i+iai+i插入SSS
  3. aaa中删除aia_iai。注意,aia_iai右边所有元素的索引将减少111

注意,nnn次操作后,aaa将为空。

现在,史塔克将构造一个新数组bbb,这个数组以SSS降序排列。形式上,bbb是一个大小为∣S∣|S|S的数组,其中bib_ibiSSS的第iii大元素(1≤i≤∣S∣1\leq i\leq|S|1iS)。

求史塔克操作后可以产生的字典序最大‡^\ddagger的数组bbb

†^\dagger集合只能包含唯一的元素。插入一个已经存在于集合中的元素不会改变集合的元素。

‡^\ddagger如果且仅当以下情况之一成立时,数组ppp在字典序上大于序列qqq

  • qqqppp的前缀,但p≠qp≠qp=q
  • 或者在数组pppqqq不同的第一个位置上,数组ppp中有一个比qqq中对应元素更大的元素。

注意,[3,1,4,1,5][3,1,4,1,5][3,1,4,1,5] 按字典序大于[3,1,3][3,1,3][3,1,3][ ][\,][][3,1,4,1][3,1,4,1][3,1,4,1],但不大于[3,1,4,1,5,9][3,1,4,1,5,9][3,1,4,1,5,9][3,1,4,1,5][3,1,4,1,5][3,1,4,1,5][4][4][4]

分析:

题意为先确定所有数后再进行降序去重排序,而不是先移除的数一定在后移除的数之前。因为最后会进行排序,集合中的数越大越好,先选择前面的数后面索引iii会减小,所以先选后面的数字插入集合是最优的。

考虑集合要去重,如果数组qqq是数组ppp的前缀且p≠qp≠qp=q那么ppp的字典序大于qqq。所以需要将相同的数字减少去重达到增大数组长度的目的。即对于相同的数字,优先取其前面的数,使其索引减少,如此最终集合的长度一定可以取到nnn

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL N = 3e5 + 10;
int a[N];

bool cmp(int x, int y) {
    return x > y;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            a[i] += i;
        }
        sort(a + 1, a + 1 + n, cmp);
        for (int i = 2; i <= n; i++) {
            a[i] = min(a[i], a[i - 1] - 1);
        }
        for (int i = 1; i <= n; i++) {
            cout << a[i] << " ";
        }
        cout << endl;
    }
    return 0;
} 

D.Sum over all Substrings(动态规划)

题意:

题目两个版本的唯一区别在于对tttnnn的限制。

对于长度均为mmm的二进制†^\dagger模式ppp和二进制字符串qqq,如果对于每个iii(1≤i≤m1\leq i\leq m1im),都存在索引lllrrr满足下列要求,那么qqq称为p−goodp-goodpgood

  • 1≤l≤i≤r≤m1\leq l\leq i\leq r\leq m1lirm
  • pip_ipi是字符串ql,ql+1,…,qrq_l,q_{l+1},\ldots,q_{r}ql,ql+1,,qr的模式‡^\ddagger

对于模式ppp来说,f(p)f(p)f(p)是二进制字符串ppp(长度与模式相同)中1\mathtt{1}1个数的最小值。

给你一个大小为nnn的二进制字符串sss。求
∑i=1n∑j=inf(sisi+1…sj)\sum_{i=1}^{n} \sum_{j=i}^{n} f(s_i s_{i+1} \ldots s_j)i=1nj=inf(sisi+1sj)

即对sss的所有n(n+1)2\frac{n(n+1)}{2}2n(n+1)子串中fff的值求和。

†^\dagger二进制模式是指仅由字符0\mathtt{0}01\mathtt{1}1组成的字符串。

‡^\ddagger如果tttccc的出现次数至少为⌈m2⌉\lceil\frac{m}{2}\rceil2m,则字符ccc是长度为mmm的字符串ttt的模式。例如,0\mathtt{0}0010\mathtt{010}010的模式,1\mathtt{1}1 不是010\mathtt{010}010的模式,而0\mathtt{0}01\mathtt{1}1都是011010\mathtt{011010}011010的模式。

分析:

题意较难理解。D1D1D1的数据量可以通过暴力计算每一个子区间的答案解决。枚举所有[l,r][l,r][l,r]。设dpidp_idpi代表1−i1-i1i所有前缀的答案。发现010010010的结构可以把长度333的覆盖。长度222和长度111差不多。因此dpidp_idpi可以转移到dpi−1dp_{i-1}dpi1dpi−2dp_{i-2}dpi2dpi−3dp_{i-3}dpi3

D2D2D2枚举rrr。发现除[r,r][r,r][r,r][r−1,r][r-1,r][r1,r]以外,其他的一定是[r−2,r][r-2,r][r2,r]要在dpdpdp中是最佳转移。因此可以进行优化。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL mod = 998244353;

void solve() {
    int n;
    cin >> n;
    string s;
    cin >> s;
    s = " " + s;
    LL ans = 0;
    vector<LL> dp(n + 1, 0);//坑点,使用数组初始化会超时
    for (int i = 1; i <= n; i++) {
        LL t = ans;
        if (s[i] == '1') {
            ans += s[i] - '0';
            if (i >= 2)
                ans += (s[i] - '0' + s[i - 1] - '0' + 1) / 2;
            if (i >= 3)
                ans += dp[i - 3] + (i - 2) * ((s[i] - '0' + s[i - 1] - '0' + s[i - 2] - '0' + 2) / 3);
        } else {
            ans += dp[i - 1];
        }
        dp[i] = ans - t;
    }
    cout << ans << endl;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

E.2…3…4… Wonderful! Wonderful!(数学)

题意:

史塔克有一个长度为nnn的数组aaa,其中对于所有iii(1≤i≤n1\leq i\leq n1in),ai=ia_i=iai=i。他将选择一个正整数kkk(1≤k≤⌊n−12⌋1\leq k\leq\lfloor\frac{n-1}{2}\rfloor1k2n1) 并对aaa进行任意次数(可能是000次)的以下运算。

  • †^\daggeraaa中选择长度为2⋅k+12\cdot k+12k+1的子序列sss。他会从aaa中删除sss的前kkk个元素。为了保持完全平衡,他还将从aaa中删除sss的最后kkk个元素。

史塔克想知道对于每个kkk1≤k≤⌊n−12⌋1\leq k\leq\lfloor\frac{n-1}{2}\rfloor1k2n1),最后能有多少个数组aaa。由于史塔克不擅长计算问题,他需要你的帮助。

由于数组的数目可能太大,答案对998244353998244353998244353取模。

†^\dagger如果xxx可以通过删除几个(可能是零个或全部)元素从yyy得到,那么序列xxx就是序列yyy的子序列。例如,[1,3][1,3][1,3][1,2,3][1,2,3][1,2,3][2,3][2,3][2,3][1,2,3][1,2,3][1,2,3]的子序列。[3,1][3,1][3,1][2,1,3][2,1,3][2,1,3]不是[1,2,3][1,2,3][1,2,3]的子序列。

分析:

需要找出可能的bbb个数。可以求出长度为nnn的二进制字符串sss的个数,如果iii出现在bbb中,则si=1s_i=1si=1,否则si=0s_i=0si=0

对于给定的nnnkkk,如果存在可以从aaa得到bbb,我们称sss字符串。

对于本题,与其计算好的字符串sss,不如计算不坏的字符串的数量。

为了方便起见,只考虑0\mathtt{0}0的个数能被2k2k2k整除的字符串sss

当且仅当在sss中从左边开始的kkk000和从右边开始的kkk000之间不存在任何111时,sss的。

把左边的第kkk000和右边的第kkk000之间的所有0\mathtt{0}0压缩成一个000,并称这个新字符串为ttt。需要注意的是,ttt中将包含2k−12k-12k10\mathtt{0}00\mathtt{0}0's。我们还可以观察到,对于每一个ttt,都存在一个唯一的sss。因为nnnkkk已经被固定。因此,恰好有 xxx1\mathtt{1}1字符串sss的数量是(x+2k−12k−1){{x+2k-1}\choose{2k-1}}(2k1x+2k1) ,因为恰好有(x+2k−12k−1){{x+2k-1}\choose{2k-1}}(2k1x+2k1)个二进制字符串ttt含有2k−12k-12k10\mathtt{0}0以及xxx1\mathtt{1}1

最后,恰好(nx)−(x+2k−12k−1)\binom{n}{x}-\binom{x+2k-1}{2k-1}(xn)(2k1x+2k1)好的二进制字符串sss具有xxx1\mathtt{1}1个和n−xn-xnx0\mathtt{0}0。不需要为从111nnn的每个xxx找出这个值,因为sss0\mathtt{0}0的个数(n−xn-xnx)应该是2k2k2k的倍数。xxx中只有O(n2k)O(\frac{n}{2k})O(2kn)是有用的候选数。复杂度O(nlog⁡(n))O(n\log(n))O(nlog(n))

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL mod = 998244353;
const LL N = 1e6 + 10;

LL fac[N], inv[N];

LL pw(LL x, LL y) {
    LL res = 1;
    while (y) {
        if (y & 1) {
            res = res * x % mod;
        }
        x = x * x % mod;
        y >>= 1;
    }
    return res;
}

LL Inv(LL x) {
    return pw(x, mod - 2);
}

void init() {
    fac[0] = inv[0] = 1;
    for (int i = 1; i < N; i++) {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = Inv(fac[i]);
    }
}

LL C(LL x, LL y) {
    if (x < 0 || y < 0 || x < y)return 0;
    return fac[x] * inv[y] % mod * inv[x - y] % mod;
}

int main() {
    init();
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int k = 1; k * 2 < n; k++) {
            LL ans = 1;
            for (int t = 1; 2 * k * t < n; t++) {
                ans = (ans + C(n, 2 * k * t) - C(n - 2 * k * (t - 1) - 1, 2 * k - 1) + mod) % mod;
            }
            cout << ans << " ";
        }
        cout << endl;
    }
    return 0;
}

赛后交流

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值