夏季训练DAY2(二分&三分)
A - 例题
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个工程队(n ≤ m ≤ 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 - 二分和其他的结合
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2112
这题我另一篇博客里做了更详细的解,这里就不赘述,指路:https://blog.csdn.net/baiyifeifei/article/details/81186227
J - 三分例题
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
http://codeforces.com/problemset/problem/551/C
这题我专门写了一篇更详细的博客,这里就不再赘述,指路https://blog.csdn.net/baiyifeifei/article/details/81192435
F - 最小化最大值
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 - 自己想想就能做的二分
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;
}