抽签

题目

       你的朋友提议玩一个游戏:将写有数字的n个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片上的数字后都将其放回口袋中。如果这4个数字的和是m,就是你赢,否则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是k1, k2, …, kn时,是否存在抽取4次和为m的方案。如果存在,输出Yes;否则,输出No。(1<=n<=50, 1<=m<=1e8, 1<=ki<=1e8)

样例

输入:

n = 3, m = 10

k = 1, 3, 5

n = 3, m = 9

k = 1, 3, 5

输出:

YES

NO

 

题解

1、暴力(n四次)

int flag = 0;
for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
		for(int k=0;k<n;k++)
			for(int l=0;l<n;l++)
                if(a[i]+a[j]+a[k]+a[l]==m)
                    flag = 1;

if(flag) printf("YES\n");
else printf("NO\n");

2、最后一次二分(n³logn)

二分搜索是否有 m-x[i]-x[j]-x[k]

# include <cstdio>
# include <algorithm>

using namespace std;
const int maxn = 1e8 + 10;

int n, m;
int x[maxn];

int fin(int a)
{
	int l = 0, r = n;
	while(r > l)
	{
		int mid = (l + r) >> 1;
		if(x[mid] == a) return 1;
		else if(x[mid] < a) l = mid +1;
		else r = mid;
	}
	return 0;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%d",&x[i]);
	
	sort(x,x+n);
	int flag = 0;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			for(int k=0;k<n;k++)
				if(fin(m-x[i]-x[j]-x[k]))
					flag = 1;
	
	if(flag) printf("YES\n");
	else printf("NO\n");
	return 0;
}

3、最后两次二分(n²logn)

二分搜索 m-x[i]-x[j]

# include <cstdio>
# include <algorithm>

using namespace std;
const int maxn = 10000;
int x[maxn], k[maxn*maxn];
int nu = 0; 

int fin(int a)
{
	int l = 0, r = nu;
	
	while(r > l)
	{
		int mid = (l + r) >> 1;
		if(k[mid]==a) return 1;
		if(a > k[mid]) l = mid+1;
		else r = mid;
	}
	return 0;
}

int main()
{
	int n, m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%d",&x[i]);
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			k[nu++] = x[i] + x[j];
	sort(k,k+nu);
	
	int flag = 0;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			if(fin(m-x[i]-x[j]))
				flag = 1;
	
	if(flag) printf("YES\n");
	else printf("NO\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39060776/article/details/81144753