目录
A - Drying
B - Garland
C - How Many Tables
D - Can you solve this equation?
E - CD
F - Monthly Expense
G - Aggressive cows
A - Drying
题意:
最让HSQ学长头疼的就是洗衣服了。
洗完之后,每件衣服都有一定单位水分ai。
在不使用烘干器的情况下,每件衣服每分钟自然流失1个单位水分。
但如果使用了烘干机则每分钟流失K个单位水分。
令人遗憾是HSQ所在的宿舍楼只有1台烘干机,而每台烘干机同时只能烘干1件衣服。
请问要想烘干N件衣服最少需要多长时间?
思路:
我们二分最后的时间t。
1.当k==1时,风干和脱干就没啥区别了,特判一次。
2.当k!=1时,二分时间:
- 假设时间为T,所有水分小于T的就让他自然风干就好了;
- 水分大于T的需要使用烘干机,假设需要的时间为x,则(T-x)+k*x>=a[i],公式变形为x=ceil(a[i]-T)*1.0/(k-1)。
-
考察点:二分,思维,数学
-
坑点:int过不去
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
ll a[maxn];
int n;
ll k,maxx=-1;
bool check(ll mid)
{
ll t=0;
for(int i=1;i<=n;i++){
if(a[i]>mid)
t+=ceil((a[i]-mid)*1.0/(k-1));
}
return t<=mid;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
maxx=max(a[i],maxx);
}
scanf("%lld",&k);
if(k==1){
printf("%lld\n",maxx);
}
else{
ll l=1,r=maxx;
while(l<r){
ll mid=(l+r)/2;
if(check(mid))
r=mid;
else
l=mid+1;
}
printf("%lld\n",l);
}
}
B - Garland
题意:
给定推导式:Hi = (Hi-1 + Hi+1)/2 - 1,并给出n和H1的值。所有的Hi>=0。
求Hn的最小值。
思路:
首先,公式变形:
接下来,我们带入i==2:
其中下划线标注的为已知量,而H3的值由H2决定,以此类推。最终我们发现,我们其实是求H2的最小值,这个最小值会使后面的H3~Hn保证最小并且满足条件。
注意:我们是在二分H2的值,但是答案要求的是Hn的值。
-
考察点:二分,数学
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int n;
double A,ans;
bool check(double mid)
{
double now_h=A,h=mid;
for(int i=3;i<=n;i++){
double tmp=h;
h=2*h-now_h+2;
now_h=tmp;
if(h<1e-9)
return false;
}
ans=h;
return true;
}
int main()
{
scanf("%d",&n);
scanf("%lf",&A);
double l=0,r=100000;
ans=0;
while(r-l>1e-9){
double mid=(l+r)/2;
if(check(mid))
r=mid;
else
l=mid;
}
printf("%.2f\n",ans);
}
C - How Many Tables
题意:
你邀请了N个朋友来聚会 ,在他们之中有M个关系:
x y :代表x和y是好朋友。
如果x,y是朋友,y,z是朋友,则认为xyz都是朋友(关系的传递)
你希望朋友应该坐在一起,这样就不会出现一些问题
请问最少要准备多少张桌子?
思路:
并查集模板题。
-
考察点:并查集
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1050;
int fa[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
fa[i]=i;
}
int findf(int n)
{
while(fa[n]!=n)
n=fa[n];
return n;
}
void join(int x,int y)
{
int fx=findf(x),fy=findf(y);///fx:1 fy:3
if(fx!=fy)
fa[fy]=fx;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m,x,y;
cin>>n>>m;
init(n);
for(int i=1;i<=m;i++){
cin>>x>>y;
join(x,y);
}
int cnt=0;
for(int i=1;i<=n;i++)
if(fa[i]==i)
cnt++;
cout<<cnt<<endl;
}
}
D - Can you solve this equation?
题意:
给定方程式 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y。
现给出Y的值,求X。
思路:
二分答案模板题。
-
考察点:二分,数学
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
double cal(double x)
{
return 8*pow(x,4)+7*pow(x,3)+2*pow(x,2)+3*x+6;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
double y;
scanf("%lf",&y);
double l=0,r=100;
if(cal(l)>y||cal(r)<y)
printf("No solution!\n");
else{
double mid=(l+r)/2;
while(fabs(cal(mid)-y)>1e-6){
if(cal(mid)>y) r=mid;
else l=mid;
mid=(l+r)/2;
}
printf("%.4lf\n",mid);
}
}
}
E - CD
题意:
给定递增序列A与递增序列B,请问B中有多少元素在A中出现?
思路:
二分查找模板题。
-
考察点:二分
-
坑点:map会ME,不关输入流会TE
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
int n,m,x;
while(cin>>n>>m&&n&&m){
for(int i=0;i<n;i++)
cin>>a[i];
int cnt=0,x;
for(int i=0;i<m;i++){
cin>>x;
if(binary_search(a,a+n,x))
cnt++;
}
cout<<cnt<<"\n";
}
}
F - Monthly Expense
题意:
给出农夫在n天中每天的花费,要求把这n天分作m组,每组的天数必然是连续的。
要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值。
思路:
二分的又一经典问题:最小化最大值。
我们对最大值进行二分,假设最大值为x,我们可以将n天分成Y组。
1.Y>m ==> x过小
2.Y<m ==> x过大
3.Y==m ==> x合适
-
考察点:二分答案,思维
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int a[maxn];
int n,m;
bool check(int x)
{
int cnt=1;
int sum=0;
for(int i=1;i<=n;i++){
if(sum+a[i]<=x)
sum+=a[i];
else{
sum=a[i];
cnt++;
}
}
return cnt>m;
}
int main()
{
cin>>n>>m;
int l=0,r=0;
for(int i=1;i<=n;i++){
cin>>a[i];
r+=a[i];
l=max(a[i],l);
}
//cout<<l<<" "<<r<<endl;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))
l=mid+1;
else
r=mid-1;
}
cout<<r<<endl;
}
G - Aggressive cows
题意:
农夫养了C头牛,牛与牛之间很可能会打架,所以农夫打算把他们分开管理。
这里一共有n个牛棚,给出从左到右的坐标。
农夫想知道在安置好所有牛之后,牛牛们之间的最短距离的最大值是多少?
思路:
同F题,最大化最小值类型,对这个最短距离进行二分。
假设当前最短距离为x,算出可以安置的牛的个数Y。
1.Y>C ==> x过小
2.Y<C ==> x过大
3.Y==C ==> x合适
代码:
///不关输入流会TE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int n,c;
int a[maxn];
bool check(int x)
{
int cnt=1,pos=0;
for(int i=1;i<n;i++)
if(a[i]-a[pos]>=x)
pos=i,cnt++;
return cnt>=c;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>c;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int l=0,r=a[n-1]-a[0];
while(l<r){
int mid=(l+r)/2;
if(check(mid))
l=mid+1;
else
r=mid;
}
cout<<l-1<<"\n";
}