2021牛客暑期多校训练营4 部分题解
C.LCS
-
题意
给出 a , b , c a,b,c a,b,c三个整数,构造三个字符串 s 1 , s 2 , s 3 s_1,s_2,s_3 s1,s2,s3满足 L C S ( s 1 , s 2 ) = a , L C S ( s 2 , s 3 ) = b , L C S ( s 1 , s 3 ) = c LCS(s_1,s_2)=a,LCS(s_2,s_3)=b,LCS(s1_,s_3)=c LCS(s1,s2)=a,LCS(s2,s3)=b,LCS(s1,s3)=c。 -
解题思路
贪心构造即可,找到最小的那个,那肯定是每个人都有的,然后确定好是哪个字符串之后根据其他的值一次构造。注意情况判断。代码 1 1 1比较麻烦,代码 2 2 2为通解:考虑这三个串互相的 L C S LCS LCS为 x , y , z x,y,z x,y,z, 且 x > = y > = z x>=y>=z x>=y>=z,显然如果 x + y − n > z x+y-n>z x+y−n>z, 则无解, 所以一定有 x + y − n < = z x+y-n<=z x+y−n<=z,我们先给这三个串加上一个 z z z个 a a a的前缀, 然后就变成了一个 x − z , y − z , 0 , n − z x-z,y-z,0,n-z x−z,y−z,0,n−z的同类问题。因为 x + y − n < = z x+y-n<=z x+y−n<=z, 所以 ( x − z ) + ( y − z ) < = n − z (x-z)+(y-z)<=n-z (x−z)+(y−z)<=n−z, 所以我们给前两个串一起放上 x − z x-z x−z 个 b b b, 后两个串一起放上 y − z y-z y−z 个 c c c即可。 -
AC代码1
/**
*@filename:C
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-26 12:01
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int n,a[3],pos[3];
string s[3];
bool cmp(int i,int j){
return a[i] < a[j];
}
void solve(){
}
int main(){
for(int i = 0; i < 3; ++ i)cin >> a[i], pos[i] = i,s[i] = "";
cin >> n;
for(int i = 0; i < 3; ++ i){
if(a[i] > n){
cout << "NO" << endl;
return 0;
}
}
sort(pos,pos + 3,cmp);
for(int i = 0; i < n; ++ i){
if(i < a[pos[0]]){
s[pos[0]] += "a",s[(pos[0] + 1) % 3] += "a";
}
else{
s[pos[0]] += "b",s[(pos[0] + 1) % 3] += "c";
}
}
//剩下那个是(pos[0] + 2) % 3;
int idx = (pos[0] + 2) % 3;
for(int i = 0; i < a[idx]; ++ i){
s[idx] += s[(idx + 1) % 3][i];
}
if(n - a[idx] >= a[(idx + 2) % 3] - a[pos[0]]){
for(int i = a[idx]; i < n; ++ i){
if(i - a[idx] < a[(idx + 2) % 3] - a[pos[0]]){
s[idx] += s[(idx + 2) % 3][i];
}
else{
s[idx] += "d";
}
}
}
else{
cout << "NO" << endl;
return 0;
}
for(int i = 0; i < 3; ++ i){
cout << s[i] << endl;
}
solve();
return 0;
}
- AC代码2
/**
*@filename:C
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-26 12:01
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int n,a,b,c;
string s1,s2,s3;
void solve(){
int minn = min(a,min(b,c));
//判断情况。
if(a + b - minn > n || a + c - minn > n || b + c - minn > n){
cout << "NO" << endl;
}
else{
for(int i = 0; i < minn; ++ i){
s1 += "a";
s2 += "a";
s3 += "a";
}
for(int i = 0; i < a - minn; ++ i){
s1 += "b";
s2 += "b";
}
for(int i = 0; i < b - minn; ++ i){
s2 += "c";
s3 += "c";
}
for(int i = 0; i < c - minn; ++ i){
s1 += "d";
s3 += "d";
}
while(s1.size() < n)s1 += "e";
while(s2.size() < n)s2 += "f";
while(s3.size() < n)s3 += "g";
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
}
}
int main(){
cin >> a >> b >> c >> n;
solve();
return 0;
}
F.Just a joke
-
题意
有一个图,现在 A l i c e , B o b Alice,Bob Alice,Bob进行一个游戏,每个人进行一个操作:删除一条边或者删除一个连通块(连通块中的点也会被删掉)。 A l i c e Alice Alice先进行。当有人不能进行操作时则输掉比赛。问谁能赢得比赛。 -
解题思路
思维题。只有两种操作,删除一条边,边数-1。删除一个连通分量,点数-k,边数-(k-1)。所以每次操作都会影响边和点的和的奇偶性。故只需要判断奇偶性质即可。 -
AC代码
/**
*@filename:F
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-26 12:20
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 110 + 5;
const int P = 1e9+7;
int n,m,u,v;
void solve(){
if((n + m) & 1){
cout << "Alice" << endl;
}
else{
cout << "Bob" << endl;
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; ++ i){
cin >> u >> v;
}
solve();
return 0;
}
I.Inverse Pair
-
题意
给你一个序列 a a a,其为 1 1 1~ n n n的排列,权重为 a a a的逆序对数。你可以构造一个序列 b b b,其中 b b b的元素取值只能为 0 , 1 0,1 0,1。问新序列 c c c的最小权重。 -
解题思路
我们构造序列 b b b即为了减少逆序对的个数,那么如果 a i a_i ai后面存在 a i + 1 a_{i+1} ai+1那么我们就可以实现让 b i + 1 = 1 b_{i+1}=1 bi+1=1从而减小,其他则别无它法。所以我们可以利用树状数组来实现,统计序对个数,再用总逆序对数减去得到真正的逆序对数,然后我们通过数组 b b b记录元素位置,从而判断相邻元素的坐标情况。 -
AC代码
/**
*@filename:I
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-26 13:28
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200000 + 5;
const int P = 1e9+7;
int n,a[N],b[N],c[N];
ll sum;//统计逆序对个数。
//利用树状数组统计逆序对。
int lowbit(int x){
return x & (-x);
}
void add(int x){
for(int i = x; i <= n; i += lowbit(i)){
c[i] ++;
}
}
int query(int x){
int res = 0;
for(int i = x; i >= 1; i -= lowbit(i)){
res += c[i];
}
return res;
}
void solve(){
sum = 1LL * n * (n - 1) / 2 - sum;//应有的逆序对。
int idx = 1;
while(idx < n){
if(b[idx] > b[idx + 1])sum --,idx += 2;
else idx ++;
}
printf("%lld\n", sum);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
sum += query(a[i]);
add(a[i]);
b[a[i]] = i;//记录其位置。
}
solve();
return 0;
}
J.Average
-
题意
给定一个矩阵,求子矩阵的最大平均值和。 -
解题思路
∑ i = l 1 r 1 ∑ j = l 2 r 2 a i + b j ( r 1 − l 1 + 1 ) ( r 2 − l 2 + 1 ) \frac{\sum_{i=l_1}^{r_1}\sum_{j={l_2}}^{r_2}{a_i+b_j}}{(r_1-l_1+1)(r_2-l_2+1)} (r1−l1+1)(r2−l2+1)∑i=l1r1∑j=l2r2ai+bj= ∑ i = l 1 r 1 a i ( r 2 − l 2 + 1 ) + ∑ j = l 2 r 2 b j ( r 1 − l 1 + 1 ) ( r 1 − l 1 + 1 ) ( r 2 − l 2 + 1 ) \frac{\sum_{i=l_1}^{r_1}a_i(r_2-l_2+1)+\sum_{j={l_2}}^{r_2}{b_j(r_1-l_1+1)}}{(r_1-l_1+1)(r_2-l_2+1)} (r1−l1+1)(r2−l2+1)∑i=l1r1ai(r2−l2+1)+∑j=l2r2bj(r1−l1+1)= ∑ i = l 1 r 1 a i ( r 1 − l 1 + 1 ) + ∑ j = l 2 r 2 b j ( r 2 − l 2 + 1 ) \frac{\sum_{i=l_1}^{r_1}a_i}{(r_1-l_1+1)}+\frac{\sum_{j={l_2}}^{r_2}{b_j}}{(r_2-l_2+1)} (r1−l1+1)∑i=l1r1ai+(r2−l2+1)∑j=l2r2bj= max a ˉ + max b ˉ \max\bar a+\max \bar b maxaˉ+maxbˉ,故即求 a , b a,b a,b区间最大平均值,题中约束 a a a区间长度至少为 x x x, b b b区间长度至少为 y y y,这是典中典的问题,我们二分区间平均值去判断其是否可行,这样我们可以避免除法的干扰,利用前缀和实现即可。 -
AC代码
/**
*@filename:J
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-26 13:51
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int n,m,x,y;
double a[N],sum[N];
double solve(int n,int len){
//len为区间最小长度。
for(int i = 1; i <= n; ++ i){
scanf("%lf", &a[i]);
}
double l = -1e5,r = 1e5,mid;
while(r - l > 1e-7){
mid = (l + r) / 2.0;
//cout << mid << " ";
for(int i = 1; i <= n; ++ i){
sum[i] = sum[i - 1] + a[i] - mid;
}
double minn = 1e6,maxx = -1e6;
for(int i = len; i <= n; ++ i){
minn = min(minn,sum[i - len]);//不断维护左端最小值。
maxx = max(maxx,sum[i] - minn);//相减得到最大值。
}
if(maxx >= 0){
l = mid;
}
else{
r = mid;
}
}
return r;
}
int main(){
scanf("%d%d%d%d", &n, &m, &x, &y);
printf("%.8lf\n",solve(n,x) + solve(m,y));
return 0;
}

浙公网安备 33010602011771号