• POJ3685 Matrix —— 二分


    题目链接:http://poj.org/problem?id=3685

    Matrix
    Time Limit: 6000MS   Memory Limit: 65536K
    Total Submissions: 7378   Accepted: 2187

    Description

    Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix.

    Input

    The first line of input is the number of test case.
    For each test case there is only one line contains two integers, N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N). There is a blank line before each test case.

    Output

    For each test case output the answer on a single line.

    Sample Input

    12
    
    1 1
    
    2 1
    
    2 2
    
    2 3
    
    2 4
    
    3 1
    
    3 2
    
    3 8
    
    3 9
    
    5 1
    
    5 25
    
    5 10
    

    Sample Output

    3
    -99993
    3
    12
    100007
    -199987
    -99993
    100019
    200013
    -399969
    400031
    -99939
    

    Source

     
     
     
    题解:
    1.二分这个数mid,然后计算有多少对(i,j),使得F= i^2 + 100000 × i + j^2 - 100000 × j + i × j <= mid。如果符合,则缩小mid,否则增大mid。
    2.问:怎么计算有多少对(i,j)使得 F <= mid 呢?
    答:根据观察,式子“F =  i^2 + 100000 × i + j^2 - 100000 × j + i × j”为二元二次方程,当i确定时,F就成了关于j的一元二次方程。所以枚举i,然后计算 有多少个整数j,使得 F = j^2 + (i-1e5)*j + i^2 + i*1e5 - mid <= 0。根据高中的知识,我们需要求解出函数F的两个零点x1和x2(1<=x1<=x2<=n),然后再从区间[x1,x2]取出整数,即得到了满足约束的多对(i,j)。
     
     
     
    正确代码:(求最小的数,使得小于等于它的数的个数>=m。即为题目所求)
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const double EPS = 1e-8;
    16 const int INF = 2e9;
    17 const LL LNF = 2e18;
    18 const int MAXN = 1e3+10;
    19 
    20 LL n, m;
    21 
    22 bool test(LL tmp)
    23 {
    24     LL sum = 0;
    25     for(LL i = 1; i<=n; i++)    //枚举i。当i已确定时, 剩下的式子就是关于j的一元二次方程。求解两个根。
    26     {
    27         LL a = 1, b = i-100000, c = 1LL*i*i+1LL*i*100000-tmp;
    28         if(1LL*b*b-4LL*a*c<0) continue; //无实数根时, 下一个i
    29         LL x1 = max( 1LL, (LL)ceil((-b-sqrt(1LL*b*b-4LL*a*c))/(2*a)) ); //左根向上取整,最小只能为1。
    30         LL x2 = min( 1LL*n, (LL)floor((-b+sqrt(1LL*b*b-4LL*a*c))/(2*a)) );  //右根向下取整,最大只能为n
    31         sum += max( 0LL, x2-x1+1 ); //区间内有多少个整数
    32     }
    33     return sum>=m;
    34 }
    35 
    36 int main()
    37 {
    38     int T;
    39     scanf("%d", &T);
    40     while(T--)
    41     {
    42         scanf("%lld%lld", &n, &m);
    43         LL l = -2e10, r = 2e10;
    44         while(l<=r)     //二分答案
    45         {
    46             LL mid = (l+r)>>1;
    47             if(test(mid))
    48                 r = mid - 1;
    49             else
    50                 l = mid + 1;
    51         }
    52         printf("%lld
    ", l);
    53     }
    54 }
    View Code

    错误代码:(求最大的数,使得小于它的数的个数<m。为题目所求的上一个数)

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const double EPS = 1e-8;
    16 const int INF = 2e9;
    17 const LL LNF = 2e18;
    18 const int MAXN = 1e3+10;
    19 
    20 LL n, m;
    21 
    22 bool test(LL tmp)
    23 {
    24     LL sum = 0;
    25     for(LL i = 1; i<=n; i++)    //枚举i。当i已确定时, 剩下的式子就是关于j的一元二次方程。求解两个根。
    26     {
    27         LL a = 1, b = i-100000, c = 1LL*i*i+1LL*i*100000-tmp;
    28         if(1LL*b*b-4LL*a*c<=0) continue;
    29         LL x1 = max( 1LL, (LL)ceil((-b-sqrt(1LL*b*b-4LL*a*c))/(2*a)) ); //左根向上取整,最小只能为1。
    30         LL x2 = min( 1LL*n, (LL)floor((-b+sqrt(1LL*b*b-4LL*a*c))/(2*a)) );  //右根向下取整,最大只能为n
    31         sum += max( 0LL, x2-x1+1 ); //区间内有多少个整数
    32     }
    33     return sum<m;
    34 }
    35 
    36 int main()
    37 {
    38     int T;
    39     scanf("%d", &T);
    40     while(T--)
    41     {
    42         scanf("%lld%lld", &n, &m);
    43         LL l = -2e10, r = 2e10;
    44         while(l<=r)     //二分答案
    45         {
    46             LL mid = (l+r)>>1;
    47             if(test(mid))
    48                 l = mid + 1;
    49             else
    50                 r = mid - 1;
    51         }
    52         printf("%lld
    ", r);
    53     }
    54 }
    View Code
  • 相关阅读:
    java中如何使正在运行中的线程退出
    Java如何等待子线程执行结束
    java解析xml几种方式
    【Flask】配置参数
    【Flask】Session
    【Flask】jinja2
    【Flask】Request
    【Flask】Respones
    【Flask】路由系统
    【Flask】认识Flask
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7582559.html
Copyright © 2020-2023  润新知