[bzoj4570][scoi2016]妖怪 二分区间
2016-05-30 22:14
519 查看
写在前面的话:
本题正解是凸包而不是二分,科学做法请右转各神犇blog。以下是蒟蒻的二分做法。
我的代码在不开o2的情况下大约800ms-900ms一个点 开o2大约300ms-400ms一点。
首先设k=ab,记xi=atki,yi=dnfi
则对于每个1≤i≤n,战斗力为fk(i)=(1k+1)∗xi+(k+1)∗yi
发现这个是对勾函数,我们可以利用这个做很多事情。(就是卡常辣)
虽然看上去解并不随k单调或者有唯一极值,也找不到二分的方向,但是我们可以采取这样的策略:
1.二分时记录当前最优ans ,上次枚举的last_k和妖怪last_i,当我们枚举到一个k0时,记录当前得到最大的f(i)的妖怪为maxi。
2.如果答案比之前更优,那么直接更新last_ans,last_k和last_i,下一次二分往maxi的那条对勾函数更低的方向走。往反方向走答案肯定不会更优。(ps:这时已经知道最后答案肯定在 f(maxi)和 maxi对勾函数最低点 之间,或许可以区间-答案交替二分?好像很炫酷)
3.如果答案并不比之前优,下一次二分往last_k的方向走。注意此时什么都不更新。
4.注意实现时用last_dir代替last_k和last_i记录,因为last_k只用到它的方向。还有注意下图this_k就相当于当前二分l和r的mid。
2的正确性显然,3的正确性…并不是那么显然。你可以脑补出这样一幅图:
根据3 在this_k时答案没有更优,往右走,就会错过了左边更优的答案?
事实上上图情况并不会发生,因为对勾函数(在第一象限)是单峰的,并且严格先递减后递增。
图大概是这样,由对勾函数性质可以推出虚线部分,就不写数学证明了。
当last_k在this_k左边时同理,当maxi=last_i时显然。
顺便一提还有一个小优化:因为题中对勾函数最低点可以O(1)算,最开始二分时就不用l=eps,r=inf了,可以l=所有对勾函数最左边最低点,r=所有对勾函数最右边最低点。(我语文弱啊还是看代码吧)
.
本题正解是凸包而不是二分,科学做法请右转各神犇blog。以下是蒟蒻的二分做法。
我的代码在不开o2的情况下大约800ms-900ms一个点 开o2大约300ms-400ms一点。
首先设k=ab,记xi=atki,yi=dnfi
则对于每个1≤i≤n,战斗力为fk(i)=(1k+1)∗xi+(k+1)∗yi
发现这个是对勾函数,我们可以利用这个做很多事情。(就是卡常辣)
然后我们要二分的是k 不是二分答案!
然后我们要二分的是k 不是二分答案!
然后我们要二分的是k 不是二分答案!
虽然看上去解并不随k单调或者有唯一极值,也找不到二分的方向,但是我们可以采取这样的策略:
1.二分时记录当前最优ans ,上次枚举的last_k和妖怪last_i,当我们枚举到一个k0时,记录当前得到最大的f(i)的妖怪为maxi。
2.如果答案比之前更优,那么直接更新last_ans,last_k和last_i,下一次二分往maxi的那条对勾函数更低的方向走。往反方向走答案肯定不会更优。(ps:这时已经知道最后答案肯定在 f(maxi)和 maxi对勾函数最低点 之间,或许可以区间-答案交替二分?好像很炫酷)
3.如果答案并不比之前优,下一次二分往last_k的方向走。注意此时什么都不更新。
4.注意实现时用last_dir代替last_k和last_i记录,因为last_k只用到它的方向。还有注意下图this_k就相当于当前二分l和r的mid。
2的正确性显然,3的正确性…并不是那么显然。你可以脑补出这样一幅图:
根据3 在this_k时答案没有更优,往右走,就会错过了左边更优的答案?
事实上上图情况并不会发生,因为对勾函数(在第一象限)是单峰的,并且严格先递减后递增。
图大概是这样,由对勾函数性质可以推出虚线部分,就不写数学证明了。
当last_k在this_k左边时同理,当maxi=last_i时显然。
顺便一提还有一个小优化:因为题中对勾函数最低点可以O(1)算,最开始二分时就不用l=eps,r=inf了,可以l=所有对勾函数最左边最低点,r=所有对勾函数最右边最低点。(我语文弱啊还是看代码吧)
#include <cstdio> #include <cmath> //#include <ctime> #define N 1000005 #define INF (10000000000000ll) #define eps 1e-8 #define Min(a,b) (a<b?a:b) #define Max(a,b) (a>b?a:b) inline int RD() { static int res; static char cr; while( (cr=getchar())<'0' || cr>'9'); res=cr-'0'; while( (cr=getchar())>='0' && cr<='9') res=(res<<1)+(res<<3)+cr-'0'; return res; } int x ,y ,n; double ans; int maxi; double check(double k) { double tox=1/k+1,toy=k+1; double res=0,r; for(int i=1;i<=n;i++) { r=tox*x[i]+toy*y[i]; // if(r>ans) return -1;//实测这个没用.. if(r>res) maxi=i,res=r; } return res; } int main() { // int c1=clock(); // freopen("monster.in","r",stdin); n=RD(); double l=INF,r=eps,temp; for(int i=1;i<=n;i++) { x[i]=RD();y[i]=RD(); temp=sqrt((double)x[i]/y[i]); l=Min(l,temp); r=Max(r,temp); } double mid,res; ans=INF; int last_dir=-1; int lim=42;//保证正确性的情况下,卡时//=42000000/n; //二分42次是拍出来的.什么泥问我拿什么对拍?lim=100就好了 while(lim--) { mid=(l+r)/2; res=check(mid); if(res>ans) last_dir? l=mid: r=mid; else//res<ans { ans=res; temp=sqrt((double)x[maxi]/y[maxi]); mid<temp? l=mid: r=mid; last_dir=(mid>temp); } } printf("%.04lf",ans); // printf("\ntime %d",clock()-c1); }
.
相关文章推荐
- 快速排序里的学问:从猜数字开始
- 2015BJOI day1第二题 树的同构family
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- Search Insert Position,Search for a Range,Pow(x, n),Sqrt(x)
- Find Minimum in Rotated Sorted Array II
- [LeetCode] Sqrt(x)
- [LeetCode] Pow(x, n)
- [LeetCode] Search Insert Position
- [LeetCode] Search for a Range
- [LeetCode] Search in Rotated Sorted Array
- PAT 1057 Stack (30)
- int sqrt(int x)
- Pow(x, n)
- Find Minimum in Rotated Sorted Array
- Divide Two Integers
- 信息竞赛学习笔记:POJ3579中位数(二分)
- acm解题报告 HDU 2141 Can you find it?
- acm解题报告 HDU 2199 Can you solve this equation?
- acm解题报告 HDU 2899 Strange fuction
- acm解题报告 HDU 1969 Pie