poj3685 解题报告

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

这道题题意就是给定一个n*n的矩阵A,A(i,j)= i2 + 100000 × i + j2 - 100000 × j + i × j,求其中第M小元素

思路:这道题是《挑战程序设计竞赛》后面的练习题之一,书上是将该题划分到"查找第K大的值"这一部分

那么之后应该如何解决呢?二分答案!

假设二分到某数值是value,那么可以统计A(i,j)<=value的数目k。如果k<M,说明这个value值还不够大,

否则,答案不超过value。如此二分下去便能确定出答案。

那么如何统计上面的k呢?显然,该不等式是一个二次不等式。如果再循环i的话,那么就变成一元二次不等式了。

这样处理,便可以求出第i行内满足不等式的j的数目。这些数目求和即是k


我的代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

class Reader{
	static BufferedReader reader;
	static StringTokenizer tokenizer;
	static void init(InputStream input) {
		reader=new BufferedReader(new InputStreamReader(input));
		tokenizer=new StringTokenizer("");
	}
	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens()) {
			tokenizer=new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}
	static int nextInt() throws IOException{
		return Integer.parseInt(next());
	}
	static long nextLong() throws IOException {
		return Long.parseLong(next());
	}
}
public class Main {
    static int casenum;
    static long n,m,maxnum,minnum;
    static long cal(long b,long c) {
       double db=b;
       double dc=c;
       long detnum=b*b-4*c;
       double det=(double)detnum;
       if (det<0) return 0;
       else {
    	   double x1=(db-Math.sqrt(det))/2;
    	   double x2=(db+Math.sqrt(det))/2;
    	   long xnum2=(long)x2;
    	   double x1l=(long)x1;
    	   if (Math.abs(x1-x1l)>=1e-8) x1l=x1l+1;
    	   long xnum1=(long)x1l;
    	   if (xnum2>n) xnum2=n;
    	   if (xnum1<1) xnum1=1;
    	   if (xnum2<xnum1) return 0;
    	   else return (xnum2-xnum1+1);
       }
    }
    private static long count(long valuenum) {
    	long sum=0;
    	for (int i=1;i<=n;i++) {
    		long inum=i;
    		long b=100000-inum;
    		long c=inum*inum+100000*inum-valuenum;
    		sum+=cal(b, c);
    	}
    	return sum;
    }
    private static void deal() {
    	long left=minnum;
    	long right=maxnum;
    	long mid;
    	long ans=left;
    	while (right>=left) {
    		mid=(left+right)/2;
    		long k=count(mid);
    		if (k<m) left=mid+1;
    		else {
    			ans=mid;
    			right=mid-1;
    		}
    	}
    	System.out.println(ans);
    }
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
      Reader.init(System.in);
      casenum=Reader.nextInt();
      for (int t=1;t<=casenum;t++) {
    	  n=Reader.nextLong();
    	  m=Reader.nextLong();
    	  maxnum=n*n*2+100000*n+n*n;
    	  minnum=1*1*2-100000*n+1*1;
    	  deal();
      }
	}

}
注意能用long就用long,我本来样例过了结果WA,后来看了讨论版块,修改了下,过了里面的数据才AC。

(我修改的是count方法里面的代码,这里如果直接用循环的int类型的i乘的话就会出错)


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值