如果直接暴力进行四次循环,
O(n4)
O
(
n
4
)
的复杂度绝对会超时。
如果先进行对k排序,然后三次循环,最后一次进行二分查找。这样排序的复杂度是
O(nlog(n))
O
(
n
log
(
n
)
)
,进行的三次循环复杂度是
O(n3log(n))
O
(
n
3
log
(
n
)
)
,所以总的复杂度是
O(n3log(n))
O
(
n
3
log
(
n
)
)
。
我们不妨再次进行优化,上面的思路其实是进行检查是否存在d使得存在
kd=m−ka−kb−kc
k
d
=
m
−
k
a
−
k
b
−
k
c
,从而替换掉内测的一次循环。同刚才的思路一样,内测的两个循环是在检查是否有c和d使得
kc+kd=m−ka−kb
k
c
+
k
d
=
m
−
k
a
−
k
b
。这种情况并不能直接使用二分搜索。但是,如果预先枚举出
kc+kd
k
c
+
k
d
所得到的
n2
n
2
个数字并排好序,便可以利用二分搜索了。该算法的排序时间是
O(n2log(n))
O
(
n
2
log
(
n
)
)
,循环时间是
O(n2log(n))
O
(
n
2
log
(
n
)
)
。总的也是
O(n2log(n))
O
(
n
2
log
(
n
)
)
时间,这样就可以确信即使是n=1000也能妥善应对了。
// 输入n为卡片个数// m为有放回地抽取4张卡片后上面数字的和// k为卡片上的数字的数组int n, m, k[MAX_N];
// 保存k[c]和k[d]两个数的和的数组int kk[MAX_N * MAX_N];
// 进行二分查找,是否在kk数组中存在一个值等于m-k[a]-k[b]bool binary_search(int x){
int l = 0, r = n*n;
while(r-l>=1){
int i = (l+r)/2;
if(kk[i] == x)returntrue;
elseif (kk[i] < x) l=i+1;
else r =i;
}
returnfalse;
}
void solve(){
// 对kk数组进行赋值for(int c=0; c<n; c++){
for(int d=0;d <n; d++){
kk[c*n+d] = k[c] + k[d];
}
}
//进行排序,方便二分查找
sort(kk, kk+n*n);
bool f = false;
for(int a=0; a<n; a++){
for(int b=0; b<n; b++){
if(binary_search(m-k[a]-k[b])){
f=true;
}
}
}
if(f) puts("Yes");
elseputs("No");
}