一.题意
你的朋友提议玩一个游戏:将写有数字的n个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片上的数字后都将其放回口袋中。如果这4个数字的和是m,就是你赢,否则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是k1, k2, …, kn时,是否存在抽取4次和为m的方案。如果存在,输出Yes;否则,输出No。(1<=n<=1000,1<=m<=1e8,1<=k<=1e8)
二.解法
2.1 暴力解法
// 通过四重循环枚举所有方案
for (int a = 0; a < n; a++) {
for (int b = 0; b < n; b++) {
for (int c = 0; c < n; c++) {
for (int d = 0; d < n; d++) {
if (k[a] + k[b] + k[c] + k[d] == m) {
f = true;
}
}
}
}
}
2.2
解法
最内层循环即检查是否存在d,使得k[a]+k[b]+k[c]+k[d]==m,将d移到左边
K[d]==m-k[a]-k[b]-k[c],可以对k数组进行排序,查找速度为logn
bool BinarySearch(int x)
{
int L=0,R=N;
//x的存在范围是k[L],k[L+1],...k[R-1]
while(R-L>=1){
int mid=(L+R)/2;
if(K[mid]==x) return true;
else if (K[mid]<x) L=mid+1;
else R=mid;
}
return false;
}
void solve(){
sort(K,K+N);
bool f=false;
for(int a=0;a<N;++a)
for(int b=0;b<N;++b)
for(int c=0;c<N;++c)
if(BinarySearch(m-k[a]-k[b]-k[c]))
f=true;
if(f) puts("YES");
else puts("NO");
}
2.3
解法
着眼于内侧的两个循环,检查最内层循环即检查是否存在c,d,使得K[c]+K[d]==m-k[a]-k[b],预先枚举出k[c]+k[d]所得的n^2个数,并排好序,就可以使用二分.
循环时间和排序时间都是
void solve(){
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);
}