首页 > 代码库 > poj 3685
poj 3685
/* 给定n,有n*n个数,有aij=i * i + m * i + j * j - m * j + i * j n <= 50000 m <= 100000 求所有aij中第m大的数 还是二分答案,先根据生成的式子,求出最大的和最小的数字,然后二分答案,验证 我们发现,对于同列的数字,按照行数的增加,数字大小是递增的 根据这个性质,就很容易验证是否存在>=n*n-m+1个数字>=val了 看了题一下子就有想法了,结果却wa了一天...原因在于自作聪明地进行数学推论然后非要从同行中进行二分...最后才发现不满足递减性质...不过最后ac的时候还是很爽快的 */#include <cstdio>#include <iostream>#include <vector>#include <algorithm>#define range(i,a,b) for (long long i=a;i<=b;i++)using namespace std;typedef long long ll;const ll m = 1e5;ll n;ll M;inline ll Int(ll i,ll j){ return i * i + m * i + j * j - m * j + i * j;}//找到最小的i,满足>=valll findK(ll j,ll val){ ll l(1),r(n); while(l+1<r) { int mid = (l+r)>>1; if (Int(mid,j) >= val) r = mid; else l = mid; } //返回>=val的数字的个数 if (Int(l,j) >= val) return n-l+1; if (Int(r,j) >= val) return n-r+1; return 0;}bool test(ll val){ ll ans(0); //返回每一行的>=val的数量 range(c,1,n) { ans += findK(c,val); } return ans >= (ll)n*n - M+1; //必须要有>=n*n-M+1的数量>=ans,ans才有可能是答案}int main(){ int t; cin>>t; range(c,1,t) { cin>>n>>M; ll l(-n*m),r(n*n*3 + n*m); while(l+1<r) { ll mid = (l+r)/2; if (mid == 5101786214) { cout<<""; } if (test(mid)) { l = mid; } else { r = mid; } } if (test(r)) { cout<<r<<endl; } if (test(l)) { cout<<l<<endl; } } return 0;}
poj 3685
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。