这几天做到一个题,题意是给两组数,每组求相加和,最后看看两组求出来的和相等的个数有几个。
然后呢,我根据题意,就这么直接设计出来了这么一个东西:
#include <bits/stdc++.h>
using namespace std;
const int cxd = 5e5+5, mxn = 1e3+5;
int f[mxn], f1[cxd], g[mxn],g1[cxd];
int a, b, c, d, i, j, k, m, n, x, y, z;
long long sum;
signed main()
{
scanf("%d", &n);
while (n--)
{
scanf("%d%d", &a, &b);
for (i = 1; i <= a; i++) scanf("%d", f+i); // 遍历
for (i = 1; i <= b; i++) scanf("%d", g+i);
for (i = 1; i <= n-1; i++)
for (j = i+1; j <= n; j++) f1[f[i] + f[j]]++; // 再遍历
for (i = 1; i <= n-1; i++)
for (j = i+1; j <= n; j++) g1[g[i] + g[j]]++;
}
return 0;
}
然后我想要再遍历两个桶(f1和g1),然后感觉复杂度不太对劲,肯定是有什么地方我没想到,然后呢,我去瞄了一眼老师的答案,这个优化方式给我震惊了。因为是很简单的,但是之前没有这么优化过,就想发到博客上,当成日常记录一下,以便我以后复习的时候再看。这段代码是我用我的风格优化过的:
#include <bits/stdc++.h>
using namespace std;
const int cxd = 3e3+5, mxn = 5e5+5;
int f[cxd], g[mxn << 1];
int a, b, c, d, i, j, k, m, n, x, y, z;
long long sum;
signed main()
{
scanf("%d", &n);
while (n--){
memset(g, 0, sizeof g); //新学的函数:重置数组的方法
sum = 0;
scanf("%d%d", &a, &b);
for (i = 1; i <= a; i++){
scanf("%d", f+i);
for (j = 1; j < i; j++) g[f[i] + f[j]]++; //这波直接把赋值和桶放到一块去我是真的没想到
}
for (i = 1; i <= b; i++){
scanf("%d", f+i);
for (j = 1; j < i; j++) sum += g[f[i] + f[j]]; //总和算法,不用再跟冤种一样去遍历10的11次方复杂度的数组了,真的太妙了
}
printf("%lld\n", sum); //我再次忘记了%lld,写成了%d(哭)
}
return 0;
}
这整套流程下来可谓是简之又简啊,堪称赏心悦目(wu),总之,有四点内容:
1,新学到一个重置数组的函数,memset函数,第一个数组名,第二个重置数,第三个sizeof 数组名
2,赋值和桶放到一起操作,以及新的遍历方式,在每次读入数据时就把事情做完了,很合我心
3,总和的新方式,当然和这题的答题方式有一定关系,先存有的,没有的直接是0, 然后第二组直接把第一组存的加上去,也不用怕重复,每次相加都是独立的,就这样得出了最后的总和,哪还需要麻烦得要死的二轮循环遍历呢?
4,数组定义成long long我往往忘记,下次别这样啊要吃大亏。。
总而言之,这是今天做的这道题的一些心得。前两天第一次尝试用哈希,也尝试了很久,但是暂时不打算写心得了。
今天就到此结束吧,前两天熬夜有点晚,今天得好好睡个觉,晚安~