所以,我正在尝试解决问题:http://codeforces.com/contest/448/problem/D
知识冠军不仅仅是迷人的,他也非常聪明。虽然我们中的一些人正在学习乘法表,但冠军Bizon以他自己的方式玩得很开心。冠军Bizon绘制了一个n×m乘法表,其中第i行和第j列交叉处的元素等于i·j(表的行和列从1开始编号)。然后他被问到:表中的数字是第k个最大的数字? Bizon the Champion总是能够立即正确回答。你能重复他的成功吗?
考虑给定的乘法表。如果您以非递减顺序从表中写出所有n·m个数字,那么您写出的第k个数字将被称为第k个最大数字。
输入 单行包含整数n,m和k(1≤n,m≤5·105;1≤k≤n·m)。
输出 在n×m乘法表中打印第k个最大数字。
我做的是,我将1的二进制搜索应用于n*m
,寻找的数字正好少于k
个元素。为此,我做了以下代码:
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
ll n,m;
int f (int val);
int min (int a, int b);
int main (void)
{
int k;
cin>>n>>m>>k;
int ind = k;
ll low = 1LL;
ll high = n*m;
int ans;
while (low <= high)
{
ll mid = low + (high-low)/2;
if (f(mid) == k)
ans = mid;
else if (f(mid) < k)
low = mid+1;
else
high = mid-1;
}
cout<<ans<<"\n";
return 0;
}
int f (int val)
{
int ret = 0;
for ( int i = 1; i <= n; i++ )
{
ret = ret + min(val/i,m);
}
return ret;
}
int min (int a, int b)
{
if (a < b)
return a;
else
return b;
}
但是,我不知道为什么,但这给出了测试用例的错误答案:
input
2 2 2
output
2
我的输出结果为0
我正在学习二进制搜索,但我不知道这个实现在哪里出错了。任何帮助将不胜感激。
答案 0 :(得分:3)
忽略二进制搜索不是最快的方法这一事实,您仍然想知道它为什么不正确。
首先要清楚你想要什么以及你的f回归:
寻找具有小于它的k个元素的数字。
没有!您正在寻找k元素小于或等于的最小数字。并且您的函数f(X)
返回小于或等于X的元素数。
因此,当f(X)返回的值太小时,您知道X必须至少大1,因此low=mid+1
是正确的。但是当f(X)返回的值太大时,X可能是完美的(可能是表中出现多次的元素)。相反,当f(X)返回正确的数字时,X可能仍然太大(X可能是表中出现零次的值)。
所以当f(X)不是太小时,你能做的最好的是high=mid
而不是high=mid-1
while (low < high)
{
ll mid = low + (high-low)/2;
if (f(mid) < k)
low = mid+1;
else
high = mid;
}
注意低永远不会得到&gt;高,所以当他们平等时停下来,我们不会试图赶上ans
。而在最后低==高==答案
比赛说1秒的时间限制。在我的计算机上,带有该校正的代码可在一秒钟内解决最大尺寸问题。但我不确定判断计算机是那么快。
编辑:int
对于问题的最大尺寸而言太小,因此您无法从f返回int:
n,m和i各自适合32位,但f()的输入和输出以及k,ret,low和high都需要保持整数高达2.5e11
答案 1 :(得分:0)
import java.util.*;
public class op {
static int n,m;
static long k;
public static void main(String args[]){
Scanner s=new Scanner(System.in);
n=s.nextInt();
m=s.nextInt();
k=s.nextLong();
long start=1;
long end=n*m;
long ans=0;
while(end>=start){
long mid=start+end;
mid/=2;
long fmid=f(mid);
long gmid=g(mid);
if(fmid>=k && fmid-gmid<k){
ans=mid;
break;
}
else if(f(mid)>k){
end=mid-1;
}
else{
start=mid+1;
}
}
System.out.println(ans);
}
static long f (long val)
{
long ret = 0;
for ( int i = 1; i <= n; i++ )
{
ret = ret + Math.min(val/i,m);
}
return ret;
}
static long g (long val)
{
long ret = 0;
for ( int i = 1; i <= n; i++ )
{
if(val%i==0 && val/i<=m){
ret++;
}
}
return ret;
}
public static class Pair{
int x,y;
Pair(int a,int b){
x=a;y=b;
}
}
}