ccf中的一题多解-完美数列和find coins

1.完美数列

思路:在一个递增序列中,确定一个左端点a[i]和一个右端点a[j],使得a[j]<=a[i]*p,并且j-i最大

强行使用O(n^2)进行枚举会超时,但是不要怕,我看到了目前有两种可以解决这个问题的方法,一个是二分法,一个是two pointers方法。

①二分法 O(logn)

从左到右扫描序列中的每一个数a[i],在a[i+1]~a[n-1]进行二分查找第一个超过a[i]*p的数的位置j,不断更新j-i的值然后就可以求得最大的题目要求的量了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int n,p,a[maxn];

//在i+1到n-1范围内查找第一个大于x的数的位置 
int bin(int i,long long x)
{
	int l=i+1,r=n-1,mid;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(a[mid]<=x)
		l=mid+1;
		else
		r=mid;
	}
	return l;
}
int main()
{
	scanf("%d%d",&n,&p);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int ans=1;
	for(int i=0;i<n;i++)
	{
		int j=bin(i,(long long)a[i]*p);
		ans=max(ans,j-i);
	}
	printf("%d\n",ans);
	return 0;
}

这样子还可以进行简化,使用upper_bound函数,upper_bound(startpos,endpos,num);在区间[startpos,endpos)内查找num最大的位置。 

int main()
{
	scanf("%d%d",&n,&p);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int ans=1;
	for(int i=0;i<n;i++)
	{
        
		int j=upper_bound(a+i+1,a+n,(long long)a[i]*p)-a;
		ans=max(ans,j-i);
	}
	printf("%d\n",ans);
	return 0;
} 

 ②two pointers

思路:在这个问题中有一个性质:如果a[j]<=a[i]*p,那么对[i,j]内任意位置k,一定有a[k]<=a[i]*p也成立。令两个下标初值均为0,设置计数器count存放满足条件的最大长度。先让j增加,直到恰好条件不满足,这个时候之后,让i增加,j增加的过程继续,直到j到达序列末端。

int main()
{
	scanf("%d%d",&n,&p);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int i=0,j=0,count=1; 
	while(i<n&&j<n)
	{
        //j不断右移直到恰好不满足条件
		while(j<n&&a[j]<=(long long)a[i]*p)
		{
			count=max(count,j-i+1);
			j++;
		}
		i++;
	}
	printf("%d\n",count);
	return 0;
}

未完待续,20190916 20:23 

2.Find Coins

题目描述
Eva loves to collect coins from all over the universe, including some other planets like Mars.  One day she visited a universal shopping mall which could accept all kinds of coins as payments.  However, there was a special requirement of the payment: for each bill, she could only use exactly two coins to pay the exact amount.  Since she has as many as 105 coins with her, she definitely needs your help.  You are supposed to tell her, for any given amount of money, whether or not she can find two coins to pay for it.

输入描述:
Each input file contains one test case.  For each case, the first line contains 2 positive numbers: N (<=105, the total number of coins) and M(<=103, the amount of money Eva has to pay).  The second line contains N face values of the coins, which are all positive numbers no more than 500.  All the numbers in a line are separated by a space.


输出描述:
For each test case, print in one line the two face values V1 and V2 (separated by a space) such that V1 + V2 = M and V1 <= V2.  If such a solution is not unique, output the one with the smallest V1.  If there is no solution, output "No Solution" instead.

输入例子:
8 15
1 2 8 7 2 4 11 15

输出例子:
4 11
 

①散列法

#include<bits/stdc++.h>
using namespace std;
//solution1:散列 
const int N=1005;
int hash[N];
int main()
{
	int n,m,a;
	scanf("%d %d",&n,&m);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a);
		++hash[a];
	}
	for(int i=0;i<N;i++)
	{
		if(hash[i]&&hash[m-i])
		{
			if(i==m-i&&hash[i]<=1)
			{
				continue;
			}
			printf("%d %d\n",i,m-i);
			return 0;
		}
	}
	printf("No Solution\n");
	return 0;
} 

②二分法

//solution2:二分
int a[100010];
int bin(int left,int right,int key)
{
	int mid;
	while(left<=right)
	{
		mid=(right+left)/2;
		if(a[mid]==key)
		return mid;
		else if(a[mid]>key)
		right=mid-1;
		else left=mid+1;
	}
	return -1;
} 
int main()
{
	int i,n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	for(int i=0;i<n;i++)
	{
		int pos=bin(0,n-1,m-a[i]);
		if(pos!=-1&&i!=pos)
		{
			printf("%d %d\n",a[i],a[pos]);
			break;
		}
	}
	if(i==n)
	printf("No Solution\n");
	return 0;
}

③two pointers

先使用sort函数排序,定义i=0,j=n-1,并根据a[i]+a[j]和M的大小来进行操作(整体过程是i和j的相遇过程)

1.a[i]+a[j]==M 则找到一组方案退出循环

2.a[i]+a[j]<M  则令i+1

3.a[i]+a[j]>M  则令j-1

直到i>=j 或满足条件a时结束,结束时根据i>=j是否成立来确定解是否存在

//solution3:two pointers
const int maxn=100010;
int a[maxn];
void twopointers(int n,int m)
{
	int i=0,j=n-1;
	while(i<j)
	{
		if(a[i]+a[j]==m)
		break;
		else if(a[i]+a[j]<m)
		{
			i++;
		}
		else
		{
			j--;
		}
	}
	if(i<j)
	{
		printf("%d %d\n",a[i],a[j]);
	}
	else
	{
		printf("No Solution\n");
	}
}
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	twopointers(n,m);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值