A.Turtle and Good Strings(思维)
题意:
乌龟认为,如果存在一串字符串t_1,t_2,…,t_kt\_1,t\_2,\ldots,t\_kt_1,t_2,…,t_k(kkk是任意整数),且该字符串sss满足下列条件,那么该字符串sss就是一个好字符串:
-
k≥2k\ge 2k≥2。
-
s=t_1+t_2+…+t_ks=t\_1+t\_2+\ldots+t\_ks=t_1+t_2+…+t_k,其中+++表示连接操作。例如,abc=a+bc\texttt{abc}=\texttt{a}+\texttt{bc}abc=a+bc。
-
对于所有1≤i<j≤k1\le i\lt j\le k1≤i<j≤k,t_it\_it_i的第一个字符不等于t_jt\_jt_j的最后一个字符。
乌龟得到一个由小写拉丁字母组成的字符串sss。请告诉他sss是否是一个好字符串!
分析:
直接判断第一个字符是否与最后一个字符相等即可。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=100;
const int MOD=1000000007;
void solve(){
int n;
cin>>n;
string s;
cin>>s;
if(s[0] == s[n-1]){
cout<<"No"<<endl;
}
else{
cout<<"YES"<<endl;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--){
solve();
}
return 0;
}
B.Turtle and Piggy Are Playing a Game 2(贪心)
题意:
乌龟和小猪正在玩一个数列游戏。他们得到一个数列a_1,a_2,…,a_na\_1,a\_2,\ldots,a\_na_1,a_2,…,a_n,乌龟先来。乌龟和小猪轮流进行(因此,小乌龟做第一轮,小猪做第二轮,小乌龟做第三轮……)。
游戏过程如下
-
假设当前序列的长度为mmm。如果是m=1m=1m=1,游戏结束。
-
如果游戏没有结束,轮到乌龟,那么乌龟必须选择一个整数iii,使得1≤i≤m−11\le i\le m-11≤i≤m−1,将a_ia\_ia_i设为max(a_i,a_i+1)\max(a\_i,a\_{i+1})max(a_i,a_i+1),并删除a_i+1a\_{i+1}a_i+1。
-
如果游戏没有结束,轮到小猪,那么小猪必须选择一个整数iii,使得1≤i≤m−11\le i\le m-11≤i≤m−1,将a_ia\_ia_i设置为min(a_i,a_i+1)\min(a\_i,a\_{i+1})min(a_i,a_i+1),并删除a_i+1a\_{i+1}a_i+1。
乌龟希望最终使a_1a\_1a_1的值最大,而小猪希望最终使a_1a\_1a_1的值最小。如果双方都以最优方式下棋,求a_1a\_1a_1最终的值。
分析:
考虑贪心,想让元素尽可能大,那就每次移除最小的元素,反之就是每次移除最大的元素。
对数组进行排序,每次移除一个最大,移除一个最小,剩下的最后一个肯定就是数组中间的那个。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=100;
const int MOD=1000000007;
void solve(){
int n;
cin>>n;
vector<int>a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a.begin(),a.end());
cout<<a[n/2]<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--){
solve();
}
return 0;
}
C.Turtle and Good Pairs(思维)
题意:
乌龟会给出一个由小写拉丁字母组成的字符串sss。
乌龟认为整数对(i,j)(i,j)(i,j)(1≤i<j≤n1\le i\lt j\le n1≤i<j≤n)是令人愉快的一对整数,当且仅当存在一个整数kkk使得i≤k<ji\le k\lt ji≤k<j和以下两个条件都成立:
-
s_k≠s_k+1s\_k\ne s\_{k+1}s_k=s_k+1;
-
s_k≠s_is\_k\ne s\_is_k=s_i或s_k+1≠s_js\_{k+1}\ne s\_js_k+1=s_j。
此外,乌龟认为当且仅当s_i=s_js\_i=s\_js_i=s_j或(i,j)(i,j)(i,j)是一对令人愉快的整数时,一对整数(i,j)(i,j)(i,j)(1≤i<j≤n1\le i\lt j\le n1≤i<j≤n)才是一对好的整数。
乌龟想给字符串sss重新排序,从而使好的配对数达到最大。请帮帮他!
分析:
题目要求我们最大化好对的数量,考虑分类讨论一下哪些(i,j)(i,j)(i,j)是好对。
-
若S_i=S_jS\_i=S\_jS_i=S_j,那么(i,j)(i,j)(i,j)是一个好对。
-
若S_i≠S_jS\_i\neq S\_jS_i=S_j,且存在kkk属于(i,j)(i,j)(i,j)使得S_k≠S_iS\_k\neq S\_iS_k=S_i且S_k≠S_jS\_k\neq S\_jS_k=S_j,那么(i,j)(i,j)(i,j)是一个好对。
可以把SSS划分成若干个由相同字符组成的连续段,如果(i,j)(i,j)(i,j)为好对,则iii所在的连续段和jjj所在的连续段必然不相邻。令numnumnum为字符串SSS连续段的数量,l_il\_il_i为第iii段的长度,那么好对数量应为n×(n−1)2−∑_i=1num−1l_i×l_i+1\frac{n\times (n-1)}{2}-\sum\_{i=1}^{num-1} l\_i\times l\_{i+1}2n×(n−1)−∑_i=1num−1l_i×l_i+1,问题转化为令∑_i=1num−1l_i×l_i+1\sum\_{i=1}^{num-1} l\_i\times l\_{i+1}∑_i=1num−1l_i×l_i+1最小。这样进行构造,令每一个字符不等于上一个字符,当只剩余一个字符时,全放在字符串最后即可。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL N = 5e5 + 5, P = 13331;
struct node{
LL id, num;
bool operator<(const node &u) const
{
return num < u.num;
}
};
void solve(){
LL n;
node l[26];
cin >> n;
char c;
for (LL i = 0; i < 26; i++)
l[i].id = i, l[i].num = 0;
for (LL i = 0; i < n; i++){
cin >> c;
l[c - 'a'].num++;
}
sort(l, l + 26);
LL st = 0, ed = 25;
while (l[st].num == 0)
st++;
LL cnt = 0;
while (cnt < n){
if (cnt % 2 == 0){
if (l[ed].num == 0){
ed--;
}
cout << (char)('a' + l[ed].id);
l[ed].num--;
cnt++;
}
else{
if (l[st].num == 0){
st++;
}
cout << (char)('a' + l[st].id);
l[st].num--;
cnt++;
}
}
cout << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
LL T;
cin>>T;
while(T--){
solve();
}
return 0;
}
D1.Turtle and a MEX Problem (Easy Version)(思维)
题意:
在这个版本的问题中,你可以两次或更多次选择同一个整数。
有一天,乌龟在玩nnn个序列。假设第iii个序列的长度是l_il\_il_i。那么第iii个序列是a_i,1,a_i,2,…,a_i,l_ia\_{i,1},a\_{i,2},\ldots,a\_{i,l\_i}a_i,1,a_i,2,…,a_i,l_i。
小猪在乌龟玩耍的时候给乌龟出了一道难题。问题的陈述是:
-
一开始有一个非负整数xxx。乌龟要对这个整数进行任意次数(可能是零次)运算。
-
在每次运算中,乌龟可以选择一个整数iii,使得1≤i≤n1\le i\le n1≤i≤n,并将xxx设为mex†(x,a_i,1,a_i,2,…,a_i,l_i)\text{mex}^{\dagger}(x,a\_{i,1},a\_{i,2},\ldots,a\_{i,l\_i})mex†(x,a_i,1,a_i,2,…,a_i,l_i)。
-
乌龟被要求找出任意次数运算后xxx的最大值。
乌龟毫不费力地解决了上述问题。他将f(k)f(k)f(k)定义为当xxx的初始值为kkk时上述问题的答案。然后,小猪给了乌龟一个非负整数mmm,并让乌龟找出∑_i=0mf(i)\sum\limits\_{i=0}^m f(i)∑_i=0mf(i)的值(即f(0)+f(1)+…+f(m)f(0)+f(1)+\ldots+f(m)f(0)+f(1)+…+f(m)的值)。不幸的是,他无法解决这个问题。请帮帮他!
†mex(c_1,c_2,…,c_k)^{\dagger}\text{mex}(c\_1,c\_2,\ldots,c\_k)†mex(c_1,c_2,…,c_k)被定义为在序列ccc中不出现的最小非负整数xxx。例如,mex(2,2,0,3)\text{mex}(2,2,0,3)mex(2,2,0,3)是111,mex(1,2)\text{mex}(1,2)mex(1,2)是000。
分析:
对于每个序列,我们最多操作两次,可以得到每个序列的第二个mex2mex2mex2。那么当xxx小于最大的mex2mex2mex2时,将其变成mex2mex2mex2,否则使用xxx本身。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL N=100;
const LL MOD=1000000007;
void solve(){
LL n,m;
cin>>n>>m;
vector<pair<LL,LL>> a(n);
LL ma=0;
for(LL i=0;i<n;i++){
LL len;
cin>>len;
vector<LL> t(len+10);
for(LL j=0;j<len;j++){
LL x;
cin>>x;
if(x<len+10)
t[x]=1;
}
LL c=1;
for(LL j=0;j<=len+5 && c<=2;j++){
if(!t[j] && c==1){
a[i].first=j;
c++;
}
else if(!t[j]){
c++;
a[i].second=j;
ma = max(ma,j);
break;
}
}
}
LL ans=0;
if (m<=ma){
ans+=(m+1)*ma;
}
else{
ans+=(ma+1)*ma;
ans+=(ma+1+m)*(m-ma)/2;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
LL T;
cin>>T;
while(T--){
solve();
}
return 0;
}
D2.Turtle and a MEX Problem (Hard Version)(思维)
题意:
在这个版本的问题中,你不能两次或多次选择同一个整数。
有一天,乌龟在玩nnn个序列。假设第iii个序列的长度为l_il\_il_i。那么第iii个序列是a_i,1,a_i,2,…,a_i,l_ia\_{i,1},a\_{i,2},\ldots,a\_{i,l\_i}a_i,1,a_i,2,…,a_i,l_i。
小猪在乌龟玩耍的时候给乌龟出了一道难题。问题的陈述是
-
一开始有一个非负整数xxx。乌龟要对这个整数进行任意次数(可能是零)的运算。
-
在每一次运算中,乌龟可以选择iii中的一个整数**{1≤i≤n1\le i\le n1≤i≤n和iii**},并将xxx设为mex†(x,a_i,1,a_i,2,…,a_i,l_i)\text{mex}^{\dagger}(x,a\_{i,1},a\_{i,2},\ldots,a\_{i,l\_i})mex†(x,a_i,1,a_i,2,…,a_i,l_i)。
-
乌龟被要求找出任意次数运算后xxx的最大值。
乌龟毫不费力地解决了上述问题。他将f(k)f(k)f(k)定义为当xxx的初始值为kkk时上述问题的答案。
然后,小猪给了乌龟一个非负整数mmm,让乌龟找出∑_i=0mf(i)\sum\limits\_{i=0}^m f(i)∑_i=0mf(i)的值(即f(0)+f(1)+…+f(m)f(0)+f(1)+\ldots+f(m)f(0)+f(1)+…+f(m)的值)。不幸的是,他无法解决这个问题。请帮帮他!
†mex(c_1,c_2,…,c_k)^{\dagger}\text{mex}(c\_1,c\_2,\ldots,c\_k)†mex(c_1,c_2,…,c_k)被定义为在序列ccc中不出现的最小非负整数xxx。例如,mex(2,2,0,3)\text{mex}(2,2,0,3)mex(2,2,0,3)是111,mex(1,2)\text{mex}(1,2)mex(1,2)是000。
分析:
本题要求在一次操作中每个序列最多使用一次。 对于第iii个序列,我们建一条有向边u_i−>v_iu\_i->v\_iu_i−>v_i。一次操作xxx可以沿着一条出边移动,或者移动到一个任意点uuu,并断开它的出边。
先倒序处理一下,令b_ib\_ib_i等于iii能够到达的最大值。可知一个xxx的答案至少是f_xf\_xf_x,所有xxx的答案至少是max_i=1n{u_i}\max\_{i=1}^{n} \{u\_i\}max_i=1n{u_i};对于所有出度大于111的iii,xxx的答案至少是f_if\_if_i。
因此实现步骤为:倒序处理f_if\_if_i、记录每个点的出度、记录度大于111的最大的f_if\_if_i、记录最大的u_iu\_iu_i。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const LL N=100;
const LL MOD=1000000007;
void solve(){
LL n,m;
cin>>n>>m;
vector<pair<LL,LL>> a(n);
LL ma=0;
for (LL i=0;i<n;i++){
LL len;
cin>>len;
ma=max(ma,len);
vector<LL>t(len+10);
for (LL j=0;j<len;j++){
LL x;
cin>>x;
if(x<len+10)
t[x]=1;
}
LL c=1;
for(LL j=0;j<=len+5 && c<=2;j++){
if(!t[j] && c==1){
a[i].first=j;
c++;
}
else if(!t[j]){
c++;
a[i].second=j;
break;
}
}
}
sort(a.begin(), a.end(),
[&](pair<LL,LL> a, pair<LL,LL> b){
return a.first > b.first;
});
LL mma = 0;
vector<LL> b(ma + 10);
vector<LL> chu(ma + 10);
for (auto [x, y] :a){
mma=max(mma,x);
LL t=max(y, b[y]);
b[x]=max(b[x], t);
chu[x]++;
}
LL t2=-1;
for(auto [x, y] :a){
if (chu[x]>=2 && b[x]>t2){
t2=b[x];
}
}
LL ans=0;
for(LL i=0;i<=ma+5 && i<=m;i++){
b[i]=max({i,b[i],t2,mma});
ans+=b[i];
}
if(m>ma+5){
ans+=(ma+6+m)*(m-ma-5)/2;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
LL T;
cin>>T;
while(T--){
solve();
}
return 0;
}
E1.Turtle and Inversions (Easy Version)(动态规划)
题意:
在简易版中,111至m−1m-1m−1的每个iii都有mmm和r_i<l_i+1r\_i\lt l\_{i+1}r_i<l_i+1的约束条件。
乌龟给出了mmm个间隔[l_1,r_1],[l_2,r_2],…,[l_m,r_m][l\_1,r\_1],[l\_2,r\_2],\ldots,[l\_m,r\_m][l_1,r_1],[l_2,r_2],…,[l_m,r_m]。他认为,如果每个区间(l_i≤k_i<r_il\_i\le k\_i\lt r\_il_i≤k_i<r_i)都存在一个整数k_ik\_ik_i,并且从111到mmm的每个整数iii都有a_i=max_j=l_ik_ip_j,b_i=min_j=k_i+1r_ip_ja\_i=\max\limits\_{j=l\_i}^{k\_i}p\_j,b\_i=\min\limits\_{j=k\_i+1}^{r\_i}p\_ja_i=max_j=l_ik_ip_j,b_i=min_j=k_i+1r_ip_j,那么下面的条件成立,那么ppp这个排列就是有趣的:
max_i=1m{a_i}<min_i=1m{b_i}\max\limits\_{i=1}^m \{a\_i\}\lt \min\limits\_{i=1}^m \{b\_i\}max_i=1m{a_i}<min_i=1m{b_i}
乌龟希望你计算出长度为nnn的所有有趣排列的最大反转数,或者告诉他是否没有有趣的排列。
排列ppp的倒置是一对整数(i,j)(i,j)(i,j)(1≤i<j≤n1\le i\lt j\le n1≤i<j≤n),使得p_i>p_jp\_i\gt p\_jp_i>p_j。
分析:
把所有的数分成两类:小数(000)和大数(111),使得任何一个小数都小于任何一个大数。这样一个排列组合就可以转化为一个010101序列。
当且仅当存在一种将所有数分成两类的方法,使得在每个给定的区间[l,r][l,r][l,r]中,所有的000都在111之前,并且在该区间中至少有一个000和一个111时,这种排列才是有趣的。这样的010101序列称为有趣序列。
如果有趣的010101序列是固定的,我们可以贪心地将所有000按降序排列,将所有111按降序排列。设000的个数为xxx,111的个数为yyy。设zzz是下标对(i,j)(i,j)(i,j)的个数,其中第iii个数是111且第jjj个数是000(这样的下标对称为101010对)。那么,逆序对的最大值是x(x−1)2+y(y−1)2+z\frac{x(x-1)}{2}+\frac{y(y-1)}{2}+z2x(x−1)+2y(y−1)+z。
在这个版本中,区间是不相交的,因此可以直接应用DPDPDP。假设f_i,jf\_{i,j}f_i,j代表从111到iii的有jjj个数字111的所有数中101010对的最大数量。至于转移,如果iii是一个区间的左端点,而这个区间的右端点是ppp,那么我们可以枚举出该区间转移的000个数为kkk,111个数为p−i+1−kp-i+1-kp−i+1−k。否则,我们要考虑iii是000还是111。
答案是max_i=0nf_n,i+i(i−1)2+(n−i)(n−i−1)2\max\limits\_{i=0}^n f\_{n,i}+\frac{i(i-1)}{2}+\frac{(n-i)(n-i-1)}{2}max_i=0nf_n,i+2i(i−1)+2(n−i)(n−i−1)。
时间复杂度O(n2+m)O(n^2+m)O(n2+m)。
代码:
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 5050;
int n, m, f[maxn][maxn], a[maxn], b[maxn];
void solve() {
scanf("%d%d", &n, &m);
for (int i = 0; i <= n + 1; ++i) {
for (int j = 0; j <= n + 1; ++j) {
f[i][j] = -1e9;
}
a[i] = 0;
}
for (int i = 1, l, r; i <= m; ++i) {
scanf("%d%d", &l, &r);
a[l] = r;
}
f[0][0] = 0;
for (int i = 1; i <= n; ++i) {
if (a[i]) {
int p = a[i];
for (int j = 0; j < i; ++j) {
for (int k = 1; k <= p - i; ++k) {
f[p][j + k] = max(f[p][j + k], f[i - 1][j] + (p - i + 1 - k) * j);
}
}
i = p;
} else {
for (int j = 0; j <= i; ++j) {
f[i][j] = f[i - 1][j] + j;
if (j) {
f[i][j] = max(f[i][j], f[i - 1][j - 1]);
}
}
}
}
int ans = 0;
for (int i = 0; i <= n; ++i) {
ans = max(ans, f[n][i] + i * (i - 1) / 2 + (n - i) * (n - i - 1) / 2);
}
printf("%d\n", ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
solve();
}
return 0;
}
赛后交流
在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。
群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。
628

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



