5.29比赛记录
比赛结果:一道题都没写出来,尝试了前两道题,全部在测试点二超时
至此要注意的是在思考算法的同时尽量降低时间复杂度 不要局限在自己写的算法中,超时且无法继续优化后果断换思路 这次比赛前两道一眼看过去基本思路就全判断为全排列+判断
一开始思路就有点歪,在比赛过程针对超时 想的是如何剪枝来优化 但是一直没什么思路 其实当时有一点关于A题解的思路 但是A题花时间太多不想继续了, 转战B 又是一眼全排列 此时本人脑子已经not found 直接本能秀技 这我刚学的深搜,回溯,并且当天上午还做了到深搜题,暴力深搜直接莽, 结果就是寄,又是测试点二超时,这就是不带脑子的下场。
做题一定要注意好数据范围 慎用暴力 超时超得你六亲不认
Div.2 A
题目补充:ai + bi <= ai+1 + bi+1 翻译时少了一个等号
比赛思路:将1~n全部存储到数组中,利用next_permutation实现全排列,再循环每个排列找到符合条件的情况 耗时严重!!!
ac思路:利用可能相等的性质 a1 + b1 = a2 + b2 = a3 + b3 = ......C 常数
bi = C - ai 由于每个ai都不同 因此得到的bi也一定不一样
题目要求ai bi 都属于1~n b(min) = 1 = C - a(max) b(max) = C - a(min) = C - 1
得出递推公式C = n + 1, bi = n + 1 - ai; 时间复杂度O(n)
比赛代码
#include<iostream>
#include<algorithm>
using namespace std;
int q[110], num[110];
int main(){
int n;
cin >> n;
while(n --){
int k;
cin >> k;
for(int i = 0; i < k; i ++){
scanf("%d", &q[i]);
num[i] = i + 1;
}
do{
int flag = 1;
for(int i = 1; i < k; i ++){
long long sum1 = num[i] + q[i], sum2 = num[i - 1] + q[i - 1];
if(sum1 < sum2){
flag = 0;
break;
}
}
if(flag){
for(int i = 0; i < k; i ++)
printf("%d ", num[i]);
cout << endl;
break;
}
}while(next_permutation(num, num + k));
}
}
ac代码
#include<iostream>
using namespace std;
int main(){
int n;
cin >> n;
while(n --){
int k, num;
cin >> k;
for(int i = 0; i < k; i ++){
cin >> num;
cout << k + 1 - num << ' ';
}
cout << endl;
}
}
Div2 B
比赛思路:利用递归回溯 枚举所有的数组c 枚举思想是每次从数组a取一个数放入c 递归下一层
回到这一层时取出数组a中的数 放入数组b中的数 再递归下一层。
每次递归到数组a取完 或数组b取完 或 同时取完 就计算最大相同子序列长度 更新到
全局变量mmax(切勿定义max 他是c++的一个库函数 不可做变量使用 编译会寄)
题解思路 首先将两个数组中各数字最大长度计算出来 双指针O(n)复杂度 在遍历所有数值 找到两个数组长度相加最大的作为答案 由于数组长度限制在2e5以内 输入数值在4e5以内 最后一步可直接遍历 不会超时
比赛代码
该代码依然存在问题 仅能实现部分排列
#include<iostream>
using namespace std;
const int N = 1e6;
int cnt[N], a[N], b[N];
int mmax;
void search(int z, int x, int y, int k){
if(x == k && y == k){
int length = 0, flag = 0;
for(int i = 0, j = 1; i < k * 2 && j < k * 2;){
if(cnt[i] == cnt[j])
j ++;
else{
length = j - i;
flag = 1;
if(mmax < length)
mmax = length;
i = j;
j ++;
}
}
if(!flag)
if(mmax < k * 2) mmax = k * 2;
return;
}
else if(x == k && y < k){
for(int i = z; i <= k * 2; i ++)
cnt[i] = b[y ++];
int length = 0, flag = 0;
for(int i = 0, j = 1; i < k * 2 && j < k * 2;){
if(cnt[i] == cnt[j])
j ++;
else{
length = j - i;
flag = 1;
if(mmax < length)
mmax = length;
i = j;
j ++;
}
}
if(!flag)
if(mmax < k * 2) mmax = k * 2;
return;
}
else if(x < k && y == k){
for(int i = z; i <= k * 2; i ++)
cnt[i] = a[x ++];
int length = 0, flag = 0;
for(int i = 0, j = 1; i < k * 2 && j < k * 2;){
if(cnt[i] == cnt[j])
j ++;
else{
length = j - i;
flag = 1;
if(mmax < length)
mmax = length;
i = j;
j ++;
}
}
if(!flag)
if(mmax < k * 2) mmax = k * 2;
return;
}
else{
cnt[z ++] = a[x ++];
search(z, x, y, k);
x --;
z --;
cnt[z ++] = b[y ++];
search(z, x, y, k);
y --;
z --;
}
}
int main(){
int n;
cin >> n;
while(n --){
int k;
cin >> k;
for(int i = 0; i < k; i ++)
scanf("%d", &a[i]);
for(int i = 0; i < k; i ++)
scanf("%d", &b[i]);
search(0, 0, 0, k);
cout << mmax << endl;
mmax = 0;
}
}
ac代码
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n;
cin >> n;
while(n --){
int k, mmax = 0;
cin >> k;
int a[k + 10], b[k + 10];
for(int i = 0; i < k; i ++)
scanf("%d", &a[i]);
for(int i = 0; i < k; i ++)
scanf("%d", &b[i]);
int max1[k * 2 + 10] = {0}, max2[k * 2 + 10] = {0}, p = 0;
for(int i = 1; i < k; i ++){
if(a[i] != a[i - 1]){
max1[a[i - 1]] = max(max1[a[i - 1]], i - p);
p = i;
}
}
max1[a[k - 1]] = max(max1[a[k - 1]], k - p);
p = 0;
for(int i = 1; i < k; i ++){
if(b[i] != b[i - 1]){
max2[b[i - 1]] = max(max2[b[i - 1]], i - p);
p = i;
}
}
max2[b[k - 1]] = max(max2[b[k - 1]], k - p);
for(int i = 0; i <= k * 2; i ++){
mmax = max(mmax, max1[i] + max2[i]);
}
cout << mmax << endl;
}
}
以上为本次比赛记录
通过本次比赛,还是发现自己容易将题目的思考过程简单化, 代码实现复杂化。
对于题目只能简单的具象化, 比如B题,a + b 拼出数组 c 然后真就直接排列组合出c 在去找最大子长度 时间复杂度必定超时, 并且代码实现也更加复杂。
在做题时一定要多想一下,要多想, 找出这套流程本质的规律来实现,不能跟着题走。