A.Maximise The Score(贪心)
题意:
白板上写着 2n2n2n 个正整数。你觉得无聊,决定用白板上的数字玩一个单人游戏。
开始时,你的分数为000。你可以通过走下面的棋nnn次来增加你的分数:
- 选择写在白板上的两个整数xxx和yyy。
- 将min(x,y)\min(x,y)min(x,y)加到您的分数中。
- 擦去白板上的xxx和yyy。
注意,在走完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中,不存在两个不同的索引iii和jjj(1≤i,j<n1\leq i,j \lt n1≤i,j<n;i≠ji\neq ji=j),使得pip_ipi整除pjp_jpj和pi+1p_{i+1}pi+1整除pj+1p_{j+1}pj+1。(1≤i,j<n1\leq i,j \lt n1≤i,j<n;i≠ji\neq ji=j)。
在此问题的限制条件下,可以证明至少存在一个ppp。
†^\dagger†长度为nnn的排列是由nnn个不同的整数组成的数组,这些整数从111到nnn依次排列。例如,[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次:
- 选择一个序号iii,使得1≤i≤∣a∣1\leq i\leq|a|1≤i≤∣a∣。
- †^\dagger†将ai+ia_i+iai+i插入SSS。
- 从aaa中删除aia_iai。注意,aia_iai右边所有元素的索引将减少111。
注意,nnn次操作后,aaa将为空。
现在,史塔克将构造一个新数组bbb,这个数组以SSS降序排列。形式上,bbb是一个大小为∣S∣|S|∣S∣的数组,其中bib_ibi是SSS的第iii大元素(1≤i≤∣S∣1\leq i\leq|S|1≤i≤∣S∣)。
求史塔克操作后可以产生的字典序最大‡^\ddagger‡的数组bbb。
†^\dagger†集合只能包含唯一的元素。插入一个已经存在于集合中的元素不会改变集合的元素。
‡^\ddagger‡如果且仅当以下情况之一成立时,数组ppp在字典序上大于序列qqq:
- qqq是ppp的前缀,但p≠qp≠qp=q;
- 或者在数组ppp和qqq不同的第一个位置上,数组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(动态规划)
题意:
题目两个版本的唯一区别在于对ttt和nnn的限制。
对于长度均为mmm的二进制†^\dagger†模式ppp和二进制字符串qqq,如果对于每个iii(1≤i≤m1\leq i\leq m1≤i≤m),都存在索引lll和rrr满足下列要求,那么qqq称为p−goodp-goodp−good:
- 1≤l≤i≤r≤m1\leq l\leq i\leq r\leq m1≤l≤i≤r≤m
- 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=1∑nj=i∑nf(sisi+1…sj)
即对sss的所有n(n+1)2\frac{n(n+1)}{2}2n(n+1)子串中fff的值求和。
†^\dagger†二进制模式是指仅由字符0\mathtt{0}0和1\mathtt{1}1组成的字符串。
‡^\ddagger‡如果ttt中ccc的出现次数至少为⌈m2⌉\lceil\frac{m}{2}\rceil⌈2m⌉,则字符ccc是长度为mmm的字符串ttt的模式。例如,0\mathtt{0}0是010\mathtt{010}010的模式,1\mathtt{1}1 不是010\mathtt{010}010的模式,而0\mathtt{0}0和1\mathtt{1}1都是011010\mathtt{011010}011010的模式。
分析:
题意较难理解。D1D1D1的数据量可以通过暴力计算每一个子区间的答案解决。枚举所有[l,r][l,r][l,r]。设dpidp_idpi代表1−i1-i1−i所有前缀的答案。发现010010010的结构可以把长度333的覆盖。长度222和长度111差不多。因此dpidp_idpi可以转移到dpi−1dp_{i-1}dpi−1、dpi−2dp_{i-2}dpi−2、dpi−3dp_{i-3}dpi−3。
D2D2D2枚举rrr。发现除[r,r][r,r][r,r]、[r−1,r][r-1,r][r−1,r]以外,其他的一定是[r−2,r][r-2,r][r−2,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 n1≤i≤n),ai=ia_i=iai=i。他将选择一个正整数kkk(1≤k≤⌊n−12⌋1\leq k\leq\lfloor\frac{n-1}{2}\rfloor1≤k≤⌊2n−1⌋) 并对aaa进行任意次数(可能是000次)的以下运算。
- †^\dagger†从aaa中选择长度为2⋅k+12\cdot k+12⋅k+1的子序列sss。他会从aaa中删除sss的前kkk个元素。为了保持完全平衡,他还将从aaa中删除sss的最后kkk个元素。
史塔克想知道对于每个kkk(1≤k≤⌊n−12⌋1\leq k\leq\lfloor\frac{n-1}{2}\rfloor1≤k≤⌊2n−1⌋),最后能有多少个数组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。
对于给定的nnn和kkk,如果存在可以从aaa得到bbb,我们称sss为好字符串。
对于本题,与其计算好的字符串sss,不如计算不坏的字符串的数量。
为了方便起见,只考虑0\mathtt{0}0的个数能被2k2k2k整除的字符串sss 。
当且仅当在sss中从左边开始的kkk个000和从右边开始的kkk个000之间不存在任何111时,sss是坏的。
把左边的第kkk个000和右边的第kkk个000之间的所有0\mathtt{0}0压缩成一个000,并称这个新字符串为ttt。需要注意的是,ttt中将包含2k−12k-12k−1个0\mathtt{0}0。0\mathtt{0}0's。我们还可以观察到,对于每一个ttt,都存在一个唯一的sss。因为nnn和kkk已经被固定。因此,恰好有 xxx个1\mathtt{1}1的坏字符串sss的数量是(x+2k−12k−1){{x+2k-1}\choose{2k-1}}(2k−1x+2k−1) ,因为恰好有(x+2k−12k−1){{x+2k-1}\choose{2k-1}}(2k−1x+2k−1)个二进制字符串ttt含有2k−12k-12k−1个0\mathtt{0}0以及xxx个1\mathtt{1}1。
最后,恰好有(nx)−(x+2k−12k−1)\binom{n}{x}-\binom{x+2k-1}{2k-1}(xn)−(2k−1x+2k−1)个好的二进制字符串sss具有xxx个1\mathtt{1}1个和n−xn-xn−x个0\mathtt{0}0。不需要为从111到nnn的每个xxx找出这个值,因为sss中0\mathtt{0}0的个数(n−xn-xn−x)应该是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,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

1021

被折叠的 条评论
为什么被折叠?



