比赛地址
密码:acm2016
A - Can you solve this equation? (HDU2199)
【题意】
给出实数y,求方程8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y在0~100范围内的解。
精确到1e-4。
【分析】
令f(x)=8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 -Y,可以发现这个函数满足单调性,故可以二分答案求解。
【Code】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const double PI = acos(-1.0);
const int MAX_N = 100000 + 10;
const double EPS = 1e-10;
double y;
double calc(double x){
return 8*x*x*x*x + 7*x*x*x + 2*x*x + 3*x + 6;
}
int main()
{
int Case;
scanf("%d",&Case);
while (Case--){
scanf("%lf",&y);
double L = 0, R = 100, mid;
for (int i = 0; i < 100; i++){
mid = (R+L) / 2;
//printf("%.2f %.5f\n",mid, calc(mid));
if (calc(mid) + EPS < y) L = mid;
else R = mid;
}
if ((L <= EPS )||(R + EPS>= 100)){
printf("No solution!\n");
continue;
}
printf("%.4f\n",L);
}
}
B - The Meeting Place Cannot Be Changed (Codeforces 780B)
【题意】
给n个人,第i个人在x[i]这个位置,他的速度为v[i],在第t分钟能到的范围为
[x[i] - t * v[i], x[i] + t * v[i]],求它们相聚的最短时间。
【分析】
也是很明显如果在第t分钟可以相聚,在大于t的时间也一定可以相聚。
然后二分时间,然后O(n)的判断是否可行,注意二分L,R的边界。
判断是否可行就是看是否有一个点能让所有人都到这个点就好,只需要lmax>=rmin就好。
【Code】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const double PI = acos(-1.0);
const int MAX_N = 100000 + 10;
const double EPS = 1e-8;
double x[MAX_N], v[MAX_N];
int n;
bool check(double t)
{
double x1 = 1e9, x2 = 0;
for (int i = 0;i < n;i++){
double l = x[i] - v[i]*t;
double r = x[i] + v[i]*t;
//l = max(l,1); r = min(r,1e9);
x1 = min(x1,r);
x2 = max(x2,l);
}
if (x2<=x1) return true;
return false;
}
int main()
{
scanf("%d",&n);
for (int i = 0; i < n; i++) scanf("%lf",&x[i]);
for (int i = 0; i < n; i++) scanf("%lf",&v[i]);
double L = 0.0, R = 1e9, mid;
for (int i = 0; i < 1000; i++){
mid = (L + R) / 2;
if (check(mid)) R = mid;
else L = mid;
//printf("%d %.12f\n",check(mid),mid);
}
printf("%.12f\n",L);
return 0;
}
C - Cable master (POJ1064)
【题意】
有n个绳子,要得到k份长度相等的绳子,问绳子最长能有多长。
【分析】
显然答案具有单调性,然后二分判断就好。注意输出不能直接输出答案,那样会四舍五入可以*100取整再 *0.01
【Code】
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const int MAX_N = 20000;
double a[MAX_N];
int n,k;
bool check(double mid){
int cnt = 0;
for (int i = 0;i < n;i++){
cnt += (int) (a[i]/mid);
if (cnt>=k) return true;
}
return false;
}
int main(){
scanf("%d%d",&n,&k);
double l = 0, r = 0 , mid;
for (int i = 0;i < n;i++){
scanf("%lf", &a[i]);
r = max(r,a[i]);
}
for (int i = 0;i < 100;i++){
mid = (r + l) /2;
if (check(mid)) l = mid;
else r = mid;
//printf("%d %.5f\n", check(mid), mid);
}
printf("%.2f\n",(int)(l*100)*0.01);
return 0;
}
D - Median (POJ3579)
【题意】
给出N个数,X1到XN,会有M个数对Xi,Xj 构成|Xi - Xj|(1<=i
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const int MAX_N = 100000 + 10;
int a[MAX_N];
int n,tmp;
bool check(int x)
{
int cnt = 0;
for(int i = 0;i < n;i++)
{
int t = upper_bound(a, a + n, a[i] + x) - a;
cnt += t - i - 1;
}
if(cnt >= tmp) return true;
return false;
}
int main()
{
while(~scanf("%d", &n)){
for (int i = 0;i < n;i++) scanf("%d", &a[i]);
sort(a, a + n);
int m = n * (n - 1) / 2;
tmp = (m + 1) / 2;
int l = 0, r = a[n - 1] - a[0];
int ans;
while(l <= r)
{
int mid = (l + r) >> 1;
if (check(mid)){
ans = mid;
r = mid - 1;
}else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}
E - NPY and shot(HDU5144)
【题意】
给出初始高度和初速度,求不同角度斜抛运动可得的最长距离
【分析】
设角度为p
根据相关物理可知
vx = v * cos(p);
vy = v * sin(p);
t = (vy + sqrt(vy * vy + 2 * g * h)) / g
x = vx * t;
可以看出x随着p的变化先增后减,所以可以三分求解.
【Code】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const double PI = acos(-1.0);
const int MAX_N = 100000 + 10;
const double g = 9.8;
double h,v;
double Dist(double degree){
double vx = v * cos(degree);
double vy = v * sin(degree);
double t = (vy + sqrt(vy * vy + 2 * g * h)) / g;
return t * vx ;
}
int main()
{
int Case;
scanf("%d",&Case);
while (Case--){
scanf("%lf%lf",&h,&v);
double L = 0, R = 90;
double mid1, mid2, ans = 0;
while (fabs(R-L)>=1e-6){
mid1 = (L * 2 + R) / 3;
mid2 = (L + 2 * R) / 3;
double L1 = Dist(mid1);
double L2 = Dist(mid2);
ans = max(ans, max(L1, L2));
if (L2+1e-6>L1) L = mid1;
else R = mid2;
}
printf("%.2f\n",ans);
}
}
F - Robin Hood (Codeforces 671B)
【题意】
有n个人,每个人a[i]个物品,进行k次操作,每次都从最富有的人手里拿走一个物品给最穷的人。
问k次操作以后,物品最多的人和物品最少的人相差几个物品
【分析】
如果次数足够多的话,最后的肯定在平均值上下,小的最多被补到sum/n,大最多减少到sum/n,或者sum/n+1。
然后就二分最小值,看所有小的是否能在k次被填满 ;
二分最大值,看所有大的是否都在k次被抹平。
然后就是二分的写法,小和大的不一样,需要加等号,避免死循环。
【Code】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const double PI = acos(-1.0);
const int MAX_N = 500000 + 10;
int n, k;
int a[MAX_N];
LL calc1(int mid)
{
LL tot = 0;
for (int i = 0;i < n;i++)
if (a[i]<=mid)
tot += mid - a[i];
return tot;
}
LL calc2(int mid)
{
LL tot = 0;
for (int i = 0;i < n;i++)
if (a[i]>mid)
tot += a[i] - mid;
return tot;
}
int main()
{
scanf ("%d%d", &n, &k);
LL sum = 0LL;
for (int i = 0;i < n;i++){
scanf("%d",&a[i]);
sum += a[i];
}
sort(a, a + n);
int L = sum / n, R = (sum + n - 1) / n;
int l = 0, r = L, ansL = 0, ansR = 0;
while (l <= r){
int mid = (l + r) >> 1;
if (calc1(mid) <= k) {
ansL = mid;
l = mid + 1;
}else r = mid-1;
}
l = R;r = 1e9;
while (l <= r){
int mid = (l + r) >> 1;
if (calc2(mid) <= k) {
ansR = mid;
r =mid - 1;
}else l = mid + 1;
}
printf("%d\n",ansR - ansL);
return 0;
}
G - Vasya and String (Codeforces 676C)
【题意】
给你一个长度为n的只含a,b的字符串,最多改变其中的k个字符,求可以得到的最长的连续子序列。
【分析】
可以用二分或尺取法解决。
二分:
枚举起点,二分末点,判断这段的要替换的字符的数量是否小于等于k,这个字符数量用前缀和处理。
需要对替换a和替换b二分两遍。
尺取法:
同样需要两遍尺取,L,R为区间,
如果当前子序列L,R的需要替换的字符<=k就R++,否则L++使需要替换的字符
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
char s[100100];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
scanf("%s",s);
queue <char> Q;
int maxn=0;
int len=0;
for (int i=0; i<n; i++)
{
if (s[i]=='a')
Q.push(s[i]);
else if (len<k)
{
len++;
Q.push(s[i]);
}
else
{
maxn=max(maxn,(int)Q.size());
while (!Q.empty()&&Q.front()=='a')
Q.pop();
if (!Q.empty())
{
Q.pop();
Q.push(s[i]);
}
}
}
maxn=max(maxn,(int)Q.size());
while (!Q.empty()) Q.pop();
len=0;
for (int i=0; i<n; i++)
{
if (s[i]=='b')
Q.push(s[i]);
else if (len<k)
{
len++;
Q.push(s[i]);
}
else
{
maxn=max(maxn,(int)Q.size());
while (!Q.empty()&&Q.front()=='b')
Q.pop();
if (!Q.empty())
{
Q.pop();
Q.push(s[i]);
}
}
}
maxn=max(maxn,(int)Q.size());
printf("%d\n",maxn);
return 0;