夏季训练DAY2(二分&三分)

A - 例题

 HDU - 2141 

http://acm.hdu.edu.cn/showproblem.php?pid=2141

Can you find it?

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/Others)
Total Submission(s): 41092    Accepted Submission(s): 10012


 

Problem Description

Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.

 

 

Input

There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.

 

 

Output

For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print "NO".

 

 

Sample Input


 

3 3 3 1 2 3 1 2 3 1 2 3 3 1 4 10

 

 

Sample Output


 

Case 1: NO YES NO

 

 

Author

wangye

 

 

Source

HDU 2007-11 Programming Contest

先处理前两个序列,相加得到一个新的序列,再通过sort排序。再将待查询数与第三个序列逐个做差,到新序列中使用lower_bound进行查找。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
int obj[250050];
int num=0;
void pre_solve(int a[],int b[],int lena,int lenb)
{
	int i,j;
	int x,y,w;
	num=0;
	memset(obj,0,sizeof(obj));
	for(i=0;i<lena;i++)
	{
		x=a[i];
		for(j=0;j<lenb;j++)
		{
			y=b[j];
		
				w=x+y;
			obj[num++]=w;

		}
	}
}
int main()
{
	int lena,lenb,lenc;
	int a[505],b[505],c[505];
	int ans[1005];
	int cnt=0;
	while(cin>>lena>>lenb>>lenc)
	{
		int i,j,k;
		for(i=0;i<lena;i++) scanf("%d",&a[i]);
		for(j=0;j<lenb;j++) scanf("%d",&b[j]);
		for(k=0;k<lenc;k++) scanf("%d",&c[k]);
		int l;int lens;
		pre_solve(a,b,lena,lenb);
		sort(obj,obj+num);
		cin>>lens;
		for(l=0;l<lens;l++)
		{
			scanf("%d",&ans[l]);
		}
		printf("Case %d:\n",++cnt);
		for(l=0;l<lens;l++)
		{
			int flag=0;
			for(k=0;k<lenc;k++)
			{
				if(*lower_bound(obj,obj+num,ans[l]-c[k])==ans[l]-c[k])	{
				flag=1;break;
				}
			}
			if(flag) printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
}

 

csuoj 1023

http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1023

1023: 修路

Submit Page    Summary    Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 1007     Solved: 555    


Description

 

前段时间,某省发生干旱,B山区的居民缺乏生活用水,现在需要从A城市修一条通往B山区的路。假设有A城市通往B山区的路由m条连续的路段组成,现在将这m条路段承包给n个工程队(≤ ≤ 300)。为了修路的便利,每个工程队只能分配到连续的若干条路段(当然也可能只分配到一条路段或未分配到路段)。假设每个工程队修路的效率一样,即每修长度为1的路段所需的时间为1。现在给出路段的数量m,工程队的数量n,以及m条路段的长度(这m条路段的长度是按照从A城市往B山区的方向依次给出,每条路段的长度均小于1000),需要你计算出修完整条路所需的最短的时间(即耗时最长的工程队所用的时间)。

Input

 

第一行是测试样例的个数T ,接下来是T个测试样例,每个测试样例占2行,第一行是路段的数量m和工程队的数量n,第二行是m条路段的长度。

Output

 

对于每个测试样例,输出修完整条路所需的最短的时间。

Sample Input

2
4 3
100 200 300 400
9 4
250 100 150 400 550 200 50 700 300

Sample Output

400
900

最大值的最小值问题,在我的另一篇博客(https://blog.csdn.net/baiyifeifei/article/details/79166686)中有写,这里不再赘述

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define md(x,y) (x+y)/2  
using namespace std;
const int maxn=0x3f3f3f3f;
int main()
{
	int n,m;
	int t;
	int roar[305]; 
	while(cin>>t)
	{
		while(t--)
		{
			cin>>m>>n;
			int i;
			int up=0,low=0;
			memset(roar,0,sizeof(roar));
			for(i=0;i<m;i++)
			{
				cin>>roar[i];
				up+=roar[i];
				low=max(low,roar[i]);
			}	
			while(low<up)
			{
				int mid=md(low,up);
				int now=roar[0],num=n-1;
				for(i=1;i<m;i++)
				{
					if(roar[i]+now>mid)
					now=roar[i],num--;
					else
					now=now+roar[i];
				}
				if(num<0)
				{
					low=mid+1;
				}
				else up=mid;
			//	cout<<endl;
			}
			cout<<low<<endl;
		}
	}
	return 0;
}

Can you solve this equation?

hduoj 2199

http://acm.hdu.edu.cn/showproblem.php?pid=2199

 

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 25047    Accepted Submission(s): 10780


 

Problem Description

Now,given the equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,can you find its solution between 0 and 100;
Now please try your lucky.

 

 

Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has a real number Y (fabs(Y) <= 1e10);

 

 

Output

For each test case, you should just output one real number(accurate up to 4 decimal places),which is the solution of the equation,or “No solution!”,if there is no solution for the equation between 0 and 100.

 

 

Sample Input


 

2 100 -4

 

 

Sample Output


 

1.6152 No solution!

 

 

Author

Redow

 

可以发现这是一个简单的单调递增函数,直接二分至满足精度,不作赘述

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
const double eps=1e-4;
inline double f(double x)
{
	return 8*pow(x,4)+7*pow(x,3)+2*x*x+3*x+6;
}
inline double md(double l,double r)
{
	return (l+r)/2;
}
int main()
{
	int t;
	while(cin>>t)
	{
		double up=f(100);
		while(t--)
		{
			double x;
			cin>>x;
			if(x<6||x>up) cout<<"No solution!"<<endl; 
			else{
				double l=0,r=100;
				double mid=md(l,r);
				while(fabs(f(mid)-x)>eps)
				{
					if(f(mid)>x)
					{
						r=mid;
					}
					else
					{
						l=mid;
					}
					mid=md(l,r);
				}
				printf("%.4f\n",mid);
			}
			
		}
	}
	return 0;
}

1976: 搬运工小明

Submit Page    Summary    Time Limit: 2 Sec     Memory Limit: 128 Mb     Submitted: 355     Solved: 92    


Description

作为老人的小明非常忧伤,因为他马上要被流放到本部去了,住进全左家垅最有历史感的11舍真是一件非常荣幸的事情。
搬行李是个体力活,小明发现自己的行李太多啦,所以他决定去买很多个袋子来装走。到了超市的小明发现,不同大小的袋子居然价格一样???虽然买最大的自然最赚,但是小明是名远近闻名的环保人士,他觉得袋子只要能装下他的行李就够了,并且为了不麻烦收银的小姐姐(⊙o⊙)…,他也只会购买同一种大小的袋子。因此他希望在能装下所有行李的前提下,袋子越小越好。同时为了避免弄乱行李,小明希望同一个袋子装的是位置连续相邻的行李。
小明摸了摸口袋发现自己带的钱最多能买N个袋子,数学特别差的他不知道到底该买多大的才合适,所以想靠你来解决这个问题了。

Input

第一行为一个数字T(T<=10)表示数据组数
第二行为两个数字N(N <= 10^5)和 M(M <= 10^5)表示袋子个数和小明的行李个数
第三行为M个数字,第i个数字a[i]表示小明的第i个行李体积为a[i](0<a[i] <= 10^9)

Output

输出一行表示袋子的最小体积(整数)

Sample Input

1
3 3
1 1 1

Sample Output

1

Hint

袋子不能装下体积大于其容积的物品
多个物品满足体积之和小于等于一个袋子的容积,就能被装进

Source

2017年8月月赛

emmm这题和“修路”完全一样,也是最大值的最小值问题,不作赘述(甚至只要改一下数组的大小就好了)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
#define md(x,y) (x+y)/2
const int size=1e5+5;
int main()
{
	int w[size];
	int t;
	cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		int i;
		int up=0,low=0,mid;
		for(i=0;i<m;i++)
		{
			cin>>w[i];
			up+=w[i];
			low=max(low,w[i]);
		}
		while(low<up)
		{
			mid=md(low,up);
			int many=n-1,now=w[0];
			for(i=1;i<m;i++)
			{
				if(now+w[i]>mid)
				now=w[i],many--;
				else now+=w[i];
			}
			if(many<0) low=mid+1;
			else up=mid;
		}
		cout<<low<<endl;
		
	}
	return 0;
}

H - 二分和其他的结合

 CSU - 2112 

http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2112

这题我另一篇博客里做了更详细的解,这里就不赘述,指路:https://blog.csdn.net/baiyifeifei/article/details/81186227

J - 三分例题

 HDU - 2899 

http://acm.hdu.edu.cn/showproblem.php?pid=2899

Strange fuction

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9538    Accepted Submission(s): 6491


 

Problem Description

Now, here is a fuction:
  F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)
Can you find the minimum value when x is between 0 and 100.

 

 

Input

The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)

 

 

Output

Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.

 

 

Sample Input


 

2 100 200

 

 

Sample Output


 

-74.4291 -178.8534

 

 

Author

Redow

 

简单的三分题。三分题目主要用于求凹凸函数的极值。对于三分,我们需要做的就是最左和最右取半得到midl,midl再和最右取半得到midr(我觉得这样叫二分再二分比较合适)然后总是把远离极值点的那个mid的边界值给舍弃掉

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
#define md(x,y) (x+y)/2
typedef long long LL;
double y;
const double eps=1e-6;
inline double f(double x)
{
	return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*pow(x,2)-y*x;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>y;
		double l=0,r=100;
		while(l+eps<r)
		{
			double midl=md(l,r);
			double midr=md(midl,r);
			if(f(midl)<f(midr))
			{
				r=midr;
			}
			else l=midl;
		}
		printf("%.4f\n",f(l));
	}
	return 0;
}

K - GukiZ hates Boxes

 CodeForces - 551C 

http://codeforces.com/problemset/problem/551/C

这题我专门写了一篇更详细的博客,这里就不再赘述,指路https://blog.csdn.net/baiyifeifei/article/details/81192435

F - 最小化最大值

 POJ - 3104 

http://poj.org/problem?id=3104

Drying

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 21739   Accepted: 5485

Description

It is very hard to wash and especially to dry clothes in winter. But Jane is a very smart girl. She is not afraid of this boring process. Jane has decided to use a radiator to make drying faster. But the radiator is small, so it can hold only one thing at a time.

Jane wants to perform drying in the minimal possible time. She asked you to write a program that will calculate the minimal time for a given set of clothes.

There are n clothes Jane has just washed. Each of them took ai water during washing. Every minute the amount of water contained in each thing decreases by one (of course, only if the thing is not completely dry yet). When amount of water contained becomes zero the cloth becomes dry and is ready to be packed.

Every minute Jane can select one thing to dry on the radiator. The radiator is very hot, so the amount of water in this thing decreases by k this minute (but not less than zero — if the thing contains less than k water, the resulting amount of water will be zero).

The task is to minimize the total time of drying by means of using the radiator effectively. The drying process ends when all the clothes are dry.

Input

The first line contains a single integer n (1 ≤ n ≤ 100 000). The second line contains ai separated by spaces (1 ≤ ai ≤ 109). The third line contains k (1 ≤ k ≤ 109).

Output

Output a single integer — the minimal possible number of minutes required to dry all clothes.

Sample Input

sample input #1
3
2 3 9
5

sample input #2
3
2 3 6
5

Sample Output

sample output #1
3

sample output #2
2

Source

Northeastern Europe 2005, Northern Subregion

题意:

有一堆衣物,每秒钟可以自动干一个湿度,另有一台干燥机,其每次可以放入一件衣物,使其干燥速度变为k问让所有衣物变干的最短时间。

思路:

二分寻找答案。在判断时需要注意,当需判断的时间为tim时,令x1为一件衣物所需的最短烘干时间,则x2为自然烘干的时间(x1+x2=tim)。此时若想将衣服烘干,则k*x1+x2>ai(ai为衣服的湿度)与x1+x2=tim的方程联立,得x1>[(ai-tim)/(k-1)]([]为向上取整),最后判断是否所有衣物的总烘干时间大于tim,如大于,则此tim不成立

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
#define md(x,y) (x+y)/2
typedef long long LL;
const int size=1e5+5;
LL arr[size];
int n;int k;
inline LL up_mod(LL x,int mod)
{
	LL ans=x/mod;
	if(x%mod!=0)
	return ans+1;
	return ans;
} 
int check(LL tim)
{
	int i;
	LL lim=tim;
	for(i=0;i<n;i++)
	{
		if(arr[i]<=lim) continue;
		tim-=up_mod(arr[i]-lim,k-1);
		//cout<<tmp<<' '<<i<<' '<<temp<<' '<<lim<<' '<<arr[i]<<endl;
		if(tim<0) return 0;
	}
	return 1; 
}
int main()
{
	
	while(cin>>n)
	{
		int i;
		LL l=0,r=0;
		for(i=0;i<n;i++)
		{
			scanf("%lld",&arr[i]);
		}
		
		scanf("%d",&k);
		LL ans;
		//cout<<l<<' '<<r<<endl;
		/*for(i=l;i<=r;i++)
		{
			cout<<check(i)<<' '<<i<<endl;
			//cout<<endl;
		}*/
		for(i=0;i<n;i++)
		{
			r=max(arr[i],r);
		}
		if(k==1) {
		cout<<r<<endl;
		continue;
		}
		while(l<=r)
		{
			LL mid=md(l,r);
			if(check(mid))
			{
				ans=mid;
				r=mid-1;
			}
			else l=mid+1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

 

 

D - 自己想想就能做的二分

 POJ - 2785 

 

http://poj.org/problem?id=2785

Time Limit: 15000MS   Memory Limit: 228000K
Total Submissions: 28514   Accepted: 8594
Case Time Limit: 5000MS

Description

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 228 ) that belong respectively to A, B, C and D .

Output

For each input file, your program has to write the number quadruplets whose sum is zero.

Sample Input

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

Sample Output

5

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

题意:

给出四个数组,求各取一个数相加所得到的0的组合数有多少

思路:

将前两组和后两组分别相加得到两个新数组,然后在一个数组中二分查找另一个数组中元素的相反数,其找到的个数即为答案

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>

using namespace std;
const long long size=4005*4005;
typedef long long LL;
LL x[size],y[size];
const int len=4005;
int main()
{
	int A[len],B[len],C[len],D[len];
	int t;
	while(cin>>t)
	{
		int i;
		for(i=0;i<t;i++)
		{
			cin>>A[i]>>B[i]>>C[i]>>D[i];
		}
		int lenx=0,leny=0;
		int j;
		for(i=0;i<t;i++)
		for(j=0;j<t;j++)
		{
			x[lenx++]=A[i]+B[j];
			y[leny++]=C[i]+D[j];
		}
		//sort(x,x+lenx);
		sort(y,y+leny);
		int ans=0;
		for(int i=0;i<lenx;i++)
		{
			ans+=upper_bound(y,y+leny,-x[i])-lower_bound(y,y+leny,-x[i]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

 

posted @ 2018-07-24 21:18  Fly_White  阅读(288)  评论(0编辑  收藏  举报