Codeforces Round #715 (Div. 2)题解
题目链接
被C题卡到了,一开始没想到,不过感觉就算不被卡,也很难出D。
A题
题意:给你n个数,问你怎么排,能使得相邻两个数\(a_i,a_{i + 1}\)满足\((a_i+a_{i + 1})/2\)是整数的数对最多
思路:显然只需要先放奇数再放偶数(反过来也行)就可。
vector<int> even, odd;
int n;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
odd.clear();
even.clear();
cin >> n;
for(int i = 1 ; i <= n ; i ++)
{
int x;
cin >> x;
if(x & 1) odd.push_back(x);
else even.push_back(x);
}
for(int i = 0 ; i < odd.size() ; i ++)
cout << odd[i] << " ";
for(int i = 0 ; i < even.size() ; i ++)
cout << even[i] << " ";
cout << endl;
}
return 0;
}
B题
题意:给你一个长度为\(3n\)字符串,问你能否将它拆分成n个长度为\(3\)的"TMT"子序列
思路:类似括号匹配,只需要满足M的数量始终不比T大,然后每出现一个M后面都会对应出现一个T即可。
string s;
int n;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
cin >> n;
cin >> s;
int t = 0, m = 0, cnt = 0;
bool flag = true;
for(int i = 0 ; i < s.size() ; i ++)
{
if(s[i] == 'T')
{
t ++;
if(cnt) cnt --;
}
else
{
m ++, cnt ++;
if(m > t) flag = false;
}
}
if(t != m * 2 || cnt) flag = false;
if(flag) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
C题
题意:给你n个数,定义\(d_i = max(a_1, ..., a_i) - min(a_1, ..., a_i)\),问你怎么排能使得 \(\sum_{k = 1}^n d_k\)最小
思路:
先排序,因为扩展肯定是取比当前范围内的数大一点或者小一点的数为最佳,大更多或者小更多肯定亏。
假设当前区间维护的最大值为maxd,最小值为mind,如果有在这个范围内的数,那肯定扩展这些数最佳,当没有这个范围的数时,肯定扩展比最大值大最小的数或者比最小值小最少的数,而排序后再DP就实现了这个过程。
区间DP,f[i][j] 表示对a[i ~ j]进行处理所得的\(\sum_{k = 1}^{j - i + 1} d_k\)的最小值。
f[i][j]只能从 f[i + 1][j] 和 f[i][j - 1] 中的一个转移过来,取最优的那个转移即可。
这题需要维护最大值和最小值,因此开了结构体
有人反馈没看懂,注意,虽然看起来是往左右扩展,但是实际上的意义,从第一步,是拿不同数作为开头的计算,然后中间,假设当前已经维护了一个区间\([l, r]\),然后转移实际上是看拿l左边的数还是r右边的数放到当前区间序列的末尾。即每次往当前维护的区间后面放一个数来计算d,最后得到的就是总和d最小的序列。
struct node{
ll maxd, mind, sum;
};
node f[N][N]; //f[i][j] 表示 a[i ~ j]中所求值的最小值
int a[N], n;
int main()
{
IOS;
{
cin >> n;
for(int i = 1 ; i <= n ; i ++) cin >> a[i];
sort(a + 1, a + n + 1);
for(int i = 1 ; i <= n ; i ++)
f[i][i] = {a[i], a[i], 0};
ll maxd, mind, nowmaxd, nowmind, add1, add2;
for(int len = 2 ; len <= n; len ++)
for(int l = 1 ; l + len - 1 <= n ; l ++)
{
int r = l + len - 1;
maxd = f[l + 1][r].maxd, mind = f[l + 1][r].mind;
nowmaxd = max(maxd, f[l][l].maxd);
nowmind = min(mind, f[l][l].mind);
add1 = nowmaxd - nowmind;
maxd = f[l][r - 1].maxd, mind = f[l][r - 1].mind;
nowmaxd = max(maxd, f[r][r].maxd);
nowmind = min(mind, f[r][r].mind);
add2 = nowmaxd - nowmind;
if(f[l + 1][r].sum + add1 < f[l][r - 1].sum + add2)
{
f[l][r].sum = f[l + 1][r].sum + add1;
f[l][r].maxd = max(f[l + 1][r].maxd, f[l][l].maxd);
f[l][r].mind = min(f[l + 1][r].mind, f[l][l].mind);
}
else
{
f[l][r].sum = f[l][r - 1].sum + add2;
f[l][r].maxd = max(f[l][r - 1].maxd, f[r][r].maxd);
f[l][r].mind = min(f[l][r - 1].mind, f[r][r].mind);
}
}
cout << f[1][n].sum << endl;
}
return 0;
}
D题
这题我没做出来,也没时间了,后面再补。
题意:
思路:
E题
这题应该可以补,后面有机会补一下。
题意:
思路: