二分

传送门

A题:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 4013
using namespace std;
long long sum[N*N];
int binsearch (long long a[], int n, int key);
int main()
{
    int n;
    long long ans = 0;
    cin>> n;
    int a[N], b[N], c[N], d[N];
    for (int i=0; i<n; i++)
        cin>>a[i]>>b[i]>>c[i]>>d[i];
    for(int i=0; i<n; i++){
        for (int j=0; j<n; j++){
            sum[i*n+j] = c[i]+d[j];
        }
    }
    //for (int i=0; i<n*n; i++) cout <<sum[i] <<endl;
    sort(sum, sum+n*n);
    long long temp;
    for (int i=0; i<n; i++){
        for (int j=0; j<n; j++){
            temp = -1*(a[i]+b[j]);
            ans += binsearch(sum, n*n, temp);
        }
    }
    cout << ans << endl;
    return 0;
}

int binsearch (long long a[], int n, int key)
{
    int left = 0, right = n, mid, num;
    while (left <= right){
        mid = (left+right)/2;
        if (a[mid] == key){
            num = 1;
            for(int i=mid-1; i>-1&&a[i] == key; i--) num++;                 //①
            for(int i = mid+1; i<n&&a[i] == key; i++) num++;
            return num;
        }
        if(a[mid] < key) left = mid + 1;
        if (a[mid] > key) right = mid - 1;
    }
    return 0;
}

各种手残加脑残,都快WA哭了 大哭

①刚开始没加这几句,忽略了数组num中可能出现相等的情况,后来加上了,但是①这一行的i--又被我手残写成i++了。。。。

B题:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100013;
int a[N];
int n,c;

bool Isok (int m)
{
    int next, last = 0;
    for (int i=1; i<c; i++){										//①
        next = last + 1;
        while( next < n && a[next] - a[last] < m) next ++;
        //cout << next <<endl;
        if (next >= n) return false;
        last = next;
    }
    return true;
}
int main()
{
    scanf("%d %d",&n, &c);
    for (int i=0; i<n; i++)
        scanf("%d", &a[i]);
    sort(a, a+n);
    int left = 0, right = a[n-1] + 1;
    int mid, ans = 0;
    while (left <= right){
         mid = (left + right) >> 1;
         //printf ("left=%d right=%d mid=%d\n",left,right,mid);
         if(Isok(mid)) {
            ans = mid;
            left = mid + 1;
        }
         else right = mid - 1;
    }
    printf ("%d\n", ans);
    return 0;
}
①:第一个点是已经固定了放在0位置,所以循环从i =1,开始;

C题:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

int n, k;
const int N = 100013;
int a[N];
int ans;
bool Isok (int m)
{
    int sumt = 0;
    for (int i=n-1; i>-1; i--){
        if(a[i] > m){
            if ((a[i] - m)%(k-1))                           //①
                sumt += (a[i] - m)/(k - 1) + 1;
            else sumt += (a[i] - m)/(k - 1);
        }
        if (sumt > m) return false;
    }
    //printf ("1\n");
    return true;
}
int main()
{
    while (~scanf("%d", &n)){
        for (int i=0; i<n; i++)
            scanf("%d", &a[i]);
        scanf("%d", &k);
        sort(a, a+n);
        if (k <= 1)
        {
            printf ("%d\n", a[n-1]);
            continue ;
        }
        int left = 0, right = a[n-1]+1;
        int mid;
        ans = 0;
        while (left <= right)
        {
            mid = (left + right) >> 1;
            //printf ("m=%d\n", mid);
            if (Isok(mid)) {
                //printf ("ans = %d\n",mid);
                ans = mid;
                right = mid -1;
            }
            else left = mid + 1;
        }
        printf ("%d\n", ans);                                  //②
    }
    return 0;
}

①:这里干燥第i件衣服用吹风机时间time = (a[i] - m) / k, 取上界,不仅仅是+1;

②:手残, 把 mid 输出了;

D题:

WA到吐了,参考了一下别人的程序。

原文链接:http://blog.csdn.net/polossk/article/details/25406653

又是一个浮点数的二分题。题意是这样的,给n个木头棒子,然后他们的长度是l_i,分成k个等分,不允许边角料的拼接。求分成k等分之后的每份长度。

关键还是精度的问题。怎么说呢,因为浮点数的二分毕竟是与整数有区别的。这个区别又特别的恶心,就是搞不出来到底精度差在哪里,那后就不断的尴尬。。。

有一个解决这类浮点数二分的技巧,就是转化成整数的二分,同时新增一个res用于维护当前最大(小)限能够满足的题目要求的值。然后就是不断地更新左边界右边界,同时维护res就行了,当然最后返回res,确保精度。

这个题我放两份代码,分别是直接浮点数二分的(G++与C++分别提交均通过),还有整数二分的。


浮点二分法:

/****
  *@author	Shen
  *@title	 poj 1064
  */

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

const double eps = 1e-5;

int n, k;
double l, v[10005];
double maxa = 0;

bool test(double x)
{
  int sum = 0;
  for (int i = 0; i < n; i++)
    sum += int(v[i] / x);
  return sum >= k;
}

double Bsearch(double l, double r)
{
  while (r - l > eps)
  {
    double mid = (r + l) * 0.5;
    if (test(mid))
      l = mid;
    else r = mid;
  }
  return r;
}

void solve()
{
  maxa = 0;
  for (int i = 0; i < n; i++)
  {
    scanf("%lf", &l);
    v[i] = l;
    maxa = max(maxa, v[i]);
  }
  double ans = Bsearch(0.0, maxa);
  ans = 0.01 * int(ans * 100);
  //G++
    printf("%.2f\n", ans);
  //C++
  //  printf("%.2lf\n", ans);
}

int main()
{
  while (~scanf("%d%d", &n, &k))
    solve();
  return 0;
}

整数二分法:

/****
	*@author    Shen
	*@title     poj 1064
	*/

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

const double eps = 1e-5;

int n, k;
double l, v[10005];
double maxa = 0;

bool test(int x)
{
    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += int(v[i] / x);
    return sum >= k;
}

int Bsearch(int l, int r)
{
    int res = 0;
    while (l <= r)
    {
        int mid = (r + l) / 2;
        //printf("l = %d, r = %d, mid = %d, res = %d.\n", l, r, mid, res);
        if (test(mid))
            res = max(res, mid), l = mid + 1;
        else r = mid - 1;
    }
    return res;
}

void solve()
{
    maxa = 0;
    for (int i = 0; i < n; i++)
    {
        scanf("%lf", &l);
        l *= 100.0;
        v[i] = l;
        maxa = max(maxa, v[i]);
    }
    int ans = Bsearch(1, int(maxa));
    printf("%d.%02d\n", ans / 100, ans % 100);
}

int main()
{
    while (~scanf("%d%d", &n, &k))
        solve();
    return 0;
}

E题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MaxN = 50000 + 11;
int a[MaxN];
int l,n,M;
int rm[MaxN];
bool Isok (int mid);
int main()
{
    scanf("%d%d%d", &l, &n, &M);
    a[0] = 0;
    a[n+1] = l;
    for (int i=1; i<=n; i++)
        scanf("%d", &a[i]);
    sort (a, a+n+2);
    int left = 0, right = l + 1, mid;
    int ans = 0;
    while (left <= right){
        mid = (left + right) >> 1;
        //printf ("mid=%d\n",mid);
        if (Isok(mid)){
            left = mid + 1;
            ans = mid;
        }
        else right = mid - 1;
    }
    printf ("%d\n", ans);
    return 0;
}
bool Isok (int mid)
{
    int cnt = 0, j;
    memset (rm, 0, sizeof(rm));
    for (int i=1; i<n+1; i++){
        j = i - 1;
        while (rm[j]) j--;
        if (a[i]- a[j] < mid){
             cnt ++;
             rm[i] = 1;
        }
        if (cnt > M) return false;
    }
    j = n;
    while (rm[j]) j--;
    while (a[n+1] - a[j] < mid){
        cnt ++;
        rm[j] = 1;
        while(rm[j]) j--;
    }
    if (cnt > M) return false;
    return true;
}

虽然一次过了,但还是帖出来吧,第一次写的时候忘记sort了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值