目录
A - Hamburgers
B - River Hopscotch
C - Cup
D - Fibonacci
E - Dating with girls(1)
F - Median
G - sort
A - Hamburgers
题意:
给出一个由'B' 'C' 'S'组成的字符串A。
接下来给出三个数nb,ns,nc,分别代表你有nb个B,ns个S,nc个C。
第三行的三个数pb,ps,pc分别代表着如果你想获取一个额外的B/S/C,你需要支付pb/ps/pc元。
第四行代表你现在有r元。
问你最多能拼成多少个A?
思路:
模拟比较浪费时间,况且这一专题为二分,所以我们采用二分答案的方式。
对于二分答案,我的理解是:一个笨学生解答一元二次方程式,我可能不会任何一种解方程的方法(开平方法、配方法等),但我可以猜答案(模拟)。
在猜答案的基础之上,我又不是笨的透顶,我不想盲目的猜算答案,于是我选择一个合适区间去猜答案(二分答案),这样就可以大大减少模拟的过程。
我们猜测A的数量为x,接下来判断当前的x会花费多少钱。
1.花的钱多了==>x大了,要小一些
2.花的钱少了==>x小了,可以尝试着大一些(这个x是可行答案,但不一定是最优答案)
-
考察点:二分答案,思维
代码:
#include<bits/stdc++.h>
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
ll nb,ns,nc;
ll xb,xs,xc;
ll pb,ps,pc;
ll money;
bool check(ll x)
{
ll needbm,needsm,needcm;
needbm=(x*xb-nb)*pb;
if(needbm<0)
needbm=0;
needsm=(x*xs-ns)*ps;
if(needsm<0)
needsm=0;
needcm=(x*xc-nc)*pc;
if(needcm<0)
needcm=0;
if(needbm+needcm+needsm<=money)
return true;
else
return false;
}
int main()
{
string ss;
cin>>ss;
cin>>nb>>ns>>nc;
cin>>pb>>ps>>pc;
cin>>money;
xb=xs=xc=0;
for(int i=0; i<ss.size(); i++)
{
if(ss[i]=='B')
xb++;
if(ss[i]=='S')
xs++;
if(ss[i]=='C')
xc++;
}
if(!xb)
pb=0;
if(!xs)
ps=0;
if(!xc)
pc=0;
//cout<<xb<<" "<<xs<<" "<<xc<<endl;
ll l=0,r=10000000000000,ans;
while(l<=r)
{
ll mid=(l+r)>>1;
//cout<<mid<<endl;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
cout<<ans<<endl;
}
B - River Hopscotch
题意:
现在有一条河,河的左岸与右岸的距离为L米。
在河中有N(0<=N<=50000)个石头,每个石头距离左岸Di米。
每两个石头之间有一段距离差,你可以最多拿走M个石头,求拿走石头之后剩下的石头群中最小的距离差最大可以是多少?
思路:
二分答案的经典问题:最大化最小值。
每次假设当前的最小距离为x,接下来就想办法求出搬走多少个石头才能使得最小距离>=x。
1.数量>M ==> x距离过大,需要小一些
2.数量<=M ==>x满足条件,但可以大一些试试
-
考察点:二分答案,最大化最小值
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+100;
int a[maxn];
int l,n,m;
bool check(int x)
{
int cnt=0;
int pos=0,now_p=1;
while(now_p<=n+1)
{
if(a[now_p]-a[pos]>=x)
pos=now_p;
else
cnt++;
now_p++;
}
return cnt<=m;
}
int main()
{
cin>>l>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
a[0]=0;a[n+1]=l;
sort(a,a+2+n);
int left=0,right=l;
while(left<=right){
int mid=(left+right)/2;
//cout<<left<<" "<<right<<endl;
if(check(mid))
left=mid+1;
else
right=mid-1;
}
cout<<right<<endl;
}
C - Cup
题意:
现在有一个杯子(圆台状),杯子里有一些水。
现在给出水的体积,请你算出水的高度。
杯子底部圆的半径与杯口圆的半径已知,杯子的高度已知。
思路:
二分水的高度。
假设水的高度为x,此时我们画出杯子的竖截面图:(画工一般,请原谅)
R:杯口圆半径、r:杯底圆半径、wr:水面半径、H:杯高、x:水高(粗体为未知量,其他为已知量)
我们利用相似三角形算出wr的大小:
wr==x/H*(R-r)+r
接下来算出水的体积v与实际体积V相比:
1.v<V ==> x偏小
2.v>V ==> x偏大
3.fabs(v-V)<=1e-7 ==> x符合条件 (浮点数如何判断相等)
-
考察点:二分,数学
代码:
//1.精度:1e-7以下即可
#include<bits/stdc++.h>
#define PI acos(-1.0)
using namespace std;
const int maxn=1e5+100;
double r,R,H,V;
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%lf%lf%lf%lf",&r,&R,&H,&V);
double s=0,e=100,mid;
while((e-s)>1e-7){
mid=(e+s)/2*1.0;
double wr=mid/H*(R-r)+r; ///圆台顶部半径
double v=PI/3*(r*r+wr*wr+wr*r)*mid; ///圆台高度
if(fabs(v-V)<=1e-7)
break;
else if(v>V)
e=mid;
else
s=mid;
}
printf("%.6lf\n",mid);
}
return 0;
}
D - Fibonacci
题意:
大家都很熟悉Fibonacci序列。其实Fibonacci也可以用矩阵相乘得到:
现在请求出F(n)的后四位数字是多少?
思路:
矩阵快速幂的模板题,典中典—Fibonacci序列。
-
考察点:矩阵快速幂,结构体,运算符重载,数学
代码:
#include<iostream>
#include<cstring>
#define PI acos(-1.0)
#define mod 10000
using namespace std;
typedef long long ll;
struct node
{
ll m[4][4];
};
node operator*(node a,node b){
node c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c.m[i][j]=(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%mod;
return c;
}
node quickpower(node base,int power)
{
node result=base;
power--;
while(power){
if(power&1) result=result*base;
power>>=1;
base=base*base;
}
return result;
}
int main()
{
int n;
while(cin>>n){
if(n==-1)
break;
else if(n==0)
cout<<"0"<<endl;
else if(n==1||n==2)
cout<<"1"<<endl;
else if(n==3)
cout<<"2"<<endl;
else{
node A;
A.m[0][0]=1,A.m[0][1]=1;
A.m[1][0]=1,A.m[1][1]=0;
A=quickpower(A,n-1);
cout<<A.m[0][0]<<endl;
}
}
}
E - Dating with girls(1)
题意:
给出长度为n的序列a,请找出有多少对(x , y)满足x+y==k。
注意:我们认为1+3==4与3+1==4是不同的两对数据。
思路:
可以二分,但没有必要。用map/set就能解决。
二分的话注意去重。
-
考察点:二分,STL,思维,Map,Set
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
ll n,k,x;
cin>>n>>k;
map<ll,int> mp;
for(int i=0;i<n;i++){
cin>>x;
mp[x]=1;
}
map<ll,int>::iterator it;
int counts=0;
for(it=mp.begin();it!=mp.end();it++){
if(mp.count(k-it->first))
counts++;
}
cout<<counts<<endl;
}
}
F - Median
题意:
给出长度为n的序列a,设B==|ai - aj| ( i ! = j )。
我们把所有产生的B整合至另一个数组之中,求这个数组的中数是多少?
注意:这里的中数是指当序列长度为len时,第(len/2)小的数为中数。
思路:
首先我们先算出新数组C的长度:
接下来二分答案。
假设中数为x,则一定有len/2个数大于x。
-
考察点:二分,思维,数学
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+100;
int a[maxn];
int n,len;
bool check(int x)
{
int cnt=0;
for(int i=0; i<n; i++)
cnt+=n-(lower_bound(a,a+n,a[i]+x)-a);
return cnt>len/2;
}
int main()
{
while(~scanf("%d",&n))
{
len=n*(n-1)/2; ///差值数组的长度
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
sort(a,a+n);
int l=0,r=a[n-1]-a[0];
while(r-l>1)
{
int mid=(l+r)>>1;
if(check(mid))
l=mid;
else
r=mid;
}
printf("%d\n",l);
}
}
G - sort
题意:
中文你我?懂?
思路:
没什么好说的,不会真有人WA2发吧(bushi)。
-
考察点:排序
-
坑点:时间要求,格式输出,多组输入
代码:
///111
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000+100;
int a[maxn];
int main()
{
int n,m;
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
for(int i=0; i<n; i++)
cin>>a[i];
sort(a,a+n);
int cnt=0,r=n-1;
while(cnt!=m)
{
if(cnt)
cout<<" ";
cout<<a[r--];
cnt++;
}
cout<<"\n";
}
}