POJ3658Matrix( 双重二分+负数+死循环)

POJ 3658 Matrix

  双重二分,wa了一下午,实在不太明白为啥一写二分就会进入死循环.

  INF要设的大一些,本题设0x3f3f3f3f会wa.

  本题有负数, 二分时(l+r)/2与(l+r)>>1的结果有所不同;

  如 l=0,r=-1,则 (l+r)/2=0,而(l+r)>>1=-1,而我们需要的正确答案是-1,所以第一种二分必须写成(l+r)>>1

  以下两种二分可过:

  (l+r)>>1

/*
* FillName:     二重二分
* Created:     2016年04月02日 14时48分41秒 星期六
* Author:      Akrusher
*
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define in(n) scanf("%d",&(n))
#define in2(x1,x2) scanf("%d%d",&(x1),&(x2))
#define inll(n) scanf("%I64d",&(n))
#define inll2(x1,x2) scanf("%I64d%I64d",&(x1),&(x2))
#define inlld(n) scanf("%lld",&(n))
#define inlld2(x1,x2) scanf("%lld%lld",&(x1),&(x2))
#define inf(n) scanf("%f",&(n))
#define inf2(x1,x2) scanf("%f%f",&(x1),&(x2))
#define inlf(n) scanf("%lf",&(n))
#define inlf2(x1,x2) scanf("%lf%lf",&(x1),&(x2))
#define inc(str) scanf("%c",&(str))
#define ins(str) scanf("%s",(str))
#define out(x) printf("%d\n",(x))
#define out2(x1,x2) printf("%d %d\n",(x1),(x2))
#define outf(x) printf("%f\n",(x))
#define outlf(x) printf("%lf\n",(x))
#define outlf2(x1,x2) printf("%lf %lf\n",(x1),(x2));
#define outll(x) printf("%I64d\n",(x))
#define outlld(x) printf("%lld\n",(x))
#define outc(str) printf("%c\n",(str))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define mem(X,Y) memset(X,Y,sizeof(X));
typedef vector<int> vec;
typedef long long ll;
typedef pair<int,int> P;
const int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
const ll INF=1e12; //INF要设的大一些,本题设0x3f3f3f3f会wa
const ll mod=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const bool AC=true;

int t,n;
ll m;
ll cal(ll i,ll j){ //返回矩阵a[i][j]的值,数组会超内存
    return     i*i+j*j+100000*i-100000*j+i*j;      //int可能会爆
}
ll C(ll x){ //此处改为int会莫名奇妙的wa,返回值也得是ll
    int l,r,mid2;
    ll cnt; //此处一定要是ll
    cnt=0;
    rep(j,1,n+1){
    l=1,r=n+1;
    while(r>l){
     mid2=(r+l)/2;
     if(cal(mid2,j)>=x) r=mid2; //本题要求的是第m大的值
     else l=mid2+1;
     }
     cnt+=r-1;
     }
     return cnt;
}
int main()
{
    ll ub,lb,mid;
    in(t);
    while(t--){
        in(n);
        inlld(m);
        lb=-INF,ub=INF;            //INF要设的大一些
        while(ub>lb){
            mid=(ub+lb)>>1;        //有负数,不能写成(l+r)/2
            if(C(mid)>=m) ub=mid; //类似中位数的那个题
            else lb=mid+1;
            }
        outlld(ub-1);//最后要减1
        }
    return 0;
}

下面这种也可以过

(l+r)/2

/*
* FillName:     二重二分
* Created:     2016年04月02日 14时48分41秒 星期六
* Author:      Akrusher
*
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define in(n) scanf("%d",&(n))
#define in2(x1,x2) scanf("%d%d",&(x1),&(x2))
#define inll(n) scanf("%I64d",&(n))
#define inll2(x1,x2) scanf("%I64d%I64d",&(x1),&(x2))
#define inlld(n) scanf("%lld",&(n))
#define inlld2(x1,x2) scanf("%lld%lld",&(x1),&(x2))
#define inf(n) scanf("%f",&(n))
#define inf2(x1,x2) scanf("%f%f",&(x1),&(x2))
#define inlf(n) scanf("%lf",&(n))
#define inlf2(x1,x2) scanf("%lf%lf",&(x1),&(x2))
#define inc(str) scanf("%c",&(str))
#define ins(str) scanf("%s",(str))
#define out(x) printf("%d\n",(x))
#define out2(x1,x2) printf("%d %d\n",(x1),(x2))
#define outf(x) printf("%f\n",(x))
#define outlf(x) printf("%lf\n",(x))
#define outlf2(x1,x2) printf("%lf %lf\n",(x1),(x2));
#define outll(x) printf("%I64d\n",(x))
#define outlld(x) printf("%lld\n",(x))
#define outc(str) printf("%c\n",(str))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define mem(X,Y) memset(X,Y,sizeof(X));
typedef vector<int> vec;
typedef long long ll;
typedef pair<int,int> P;
const int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
const ll INF=1e12; //INF要设的大一些,本题设0x3f3f3f3f会wa
const ll mod=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const bool AC=true;

int t,n;
ll m;
ll cal(ll i,ll j){ //返回矩阵a[i][j]的值,数组会超内存
    return     i*i+j*j+100000*i-100000*j+i*j;      //int可能会爆
}
ll C(ll x){ //此处改为int会莫名奇妙的wa,返回值也得是ll
    int l,r,mid2;
    ll cnt; //此处一定要是ll
    cnt=0;
    rep(j,1,n+1){
    l=1,r=n+1;
    while(r>l){
     mid2=(r+l)/2;
     if(cal(mid2,j)>=x) r=mid2; //本题要求的是第m大的值
     else l=mid2+1;
     }
     cnt+=r-1;
     }
     return cnt;
}
int main()
{
    ll ub,lb,mid;
    in(t);
    while(t--){
        in(n);
        inlld(m);
        lb=-INF,ub=INF;            //INF要设的大一些
        while(ub-lb>1){
            mid=(ub+lb)/2;        //有负数,不能写成(l+r)/2
            if(C(mid)>=m) ub=mid; //类似中位数的那个题
            else lb=mid;
            }
        outlld(lb);
        }
    return 0;
}
时间: 2024-08-04 18:48:59

POJ3658Matrix( 双重二分+负数+死循环)的相关文章

二分查找中的死循环

二分算法是我们经常会用到的一个算法.它是分治法的一个应用.不过,虽然他写起来貌似很简单,但是却很容易写错.下面我们讨论一下二分的死循环问题.(这里讨论的是整数的二分问题,浮点数的二分不容易死循环) 1.查找的元素确定,值唯一或者不存在 这种情况等下,我们的流程分为三个分支:(相等.小于.大于).这类不容易死循环,代码如下: if ( data[mid] == key ) return mid; if ( data[mid] > key ) r = mid-1; else l = mid+1; 2

二分套二分 hrbeu.acm.1211Kth Largest

Kth Largest TimeLimit: 1 Second   MemoryLimit: 32 Megabyte Description There are two sequences A and B with N (1<=N<=10000) elements each. All of the elements are positive integers. Given C=A*B, where '*' representing Cartesian product, c = a*b, whe

LA 3971 (二分) Assemble

题意: 你有b块钱想要组装一台电脑.给出n个配件的种类,品质和价格,要求每个种类的配件各买一个总价格不超过b且“品质最差配件”的品质因子应尽量大. 这种情况下STL的map的确很好用,学习学习 这种最大值最小的问题可以用二分法,自己写的二分会死循环,学习一下别人的二分. 1 //#define LOCAL 2 #include <vector> 3 #include <cstdio> 4 #include <string> 5 #include <map>

你真的会二分查找吗

二分查找经常写挂,最常写挂的就是陷入一个死循环,如何避免呢? 网上有很多版本的二分代码.循环条件有:l < r的,有l+1 < r的,有l <= r的.做个总结吧. 一.首先是二分查找一个值,找到返回其下标,否则返回-1. //在a[l] ~ a[r]中查找s int binary_search(int l, int r, int s){ while(l <= r){ int m = (l+r)/2; if(a[m] == s) return m; if(a[m] < s)

二分查找注意点(转)

转载请注明:http://blog.csdn.net/zhouyelihua/article/details/46665931 二分查找的应用 二分查找作为O(log(n))时间复杂度的查找算法得到了广泛的使用. 1.在已排序的数组中查找特定的元素.或者是满足条件的第一个元素 2.数学常用的求解方程的解,也是数学家所指的对半查找. 3.程序调试中用来定位错误语句 4-. 二分查找的原始代码 int binarySearch(int A[],int left,int right,int targe

【信息学奥赛一本通 提高组】第二章 二分与三分

一.二分 二分法,在一个单调有序的集合或函数中查找一个解,每次分为左右两部分,判断解在那个部分并调整上下界,直到找到目标元素,每次二分都将舍弃一般的查找空间,因此效率很高. 二分常见模型 1.二分答案 最小值最大(或是最大值最小)问题,这类双最值问题常常选用二分法求解,也就是确定答案后,配合贪心,DP等其他算法检验这个答案是否合理,将最优化问题转化为判定性问题.例如,将长度为n的序列ai分为最多m个连续段,求所有分法中每段和的最大值的最小是多少? 2.二分查找 用具有单调性的布尔表达式求解分界点

二分查找专题总结 - 基础篇

二分查找 - 基础篇 前言 从一个有序的数组中,找到某元素的值,通常思路就是二分查找.二分查找是一个常考的知识点.同时,它也是非常容易出错的一道面试题.左右指针的位置,取值,比较是大于还是大于等于.里面细节很多.死记硬背往往容易出错,只有真正理解思路和多多练习,才能掌握不出错的"二分算法". 本篇文章是二分查找的入门篇.将会介绍最传统,最容易理解与书写的二分算法.并介绍四种二分查找的进阶问题.在理解本文的基础上,后续文章将会再分享二分的各种变形和其他模板. 原题:在有序数组中查找定值

二分的细节

满足单调性的情况下,可以用二分法找出答案,复杂度为logn 1.在整数范围内,闭区间[l,r]的二分,以l==r为结束条件.边界条件需要考虑几个问题,当l或r更新的时候范围是否有缩小(若无则选入死循环),是赋得新值之后l是否==r而不是>r; 2.根据题目设计选取mid归属于左半区间还是右半区间,假设我们要在单调递增的数组里面找第一个 >=val的值 假设a[mid]符合条件,那么可知mid的右边全都符合条件,但不知道mid的左边有没有符合条件的数字,因此在划分区间的时候不可以将mid去掉,因

二分查找总结

最近刷leetcode和lintcode,做到二分查找的部分,发现其实这种类型的题目很有规律,题目大致的分为以下几类: 1.最基础的二分查找题目,在一个有序的数组当中查找某个数,如果找到,则返回这个数在数组中的下标,如果没有找到就返回-1或者是它将会被按顺序插入的位置.这种题目继续进阶一下就是在有序数组中查找元素的上下限.继续做可以求两个区间的交集. 2.旋转数组问题,就是将一个有序数组进行旋转,然后在数组中查找某个值,其中分为数组中有重复元素和没有重复元素两种情况. 3.在杨氏矩阵中利用二分查