OJ1818《概率游戏》题解

来源:互联网 发布:sql语句中单引号 编辑:程序博客网 时间:2024/06/05 02:12
好久没写博文了,今天来一发,写个OJ的题,二分,妥了个妥!!!

 
  
分析:首先你得求求总情况吧,这个好弄,1+2+...+N-1,这是总情况。
其次,你得求求满足条件的吧,这个稍麻烦点,因为有10W数据,所以N*N断然不可,所以就理所当然的想到了二分求解,N*logN的复杂度妥妥的。
其实不到N*logN,因为你可以先把大于X的数直接剔除了,得到一个新数组b,一共有n个数,排序,这样就可以放心的二分了,先选出一个数,再二分查找另一个数,保证这个数和已选定的数之和满足条件,那么这个数前的所有数都满足条件,但是要注意避免自己加自己的情况。
这应该还不是最简,外层循环应该也打不到n,因为n个数有序,所以可以加一个记录,可以少循环很多次,水平差,所以没写出来,但也足够AC了。

代码如下:
#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;ll N,X,a[100010],b[100010],sum2,sum1=0,n=0;double sum;void init(){scanf("%d%lld",&N,&X);for(ll i=1;i<=N;i++){scanf("%lld",&a[i]);if(a[i]<X) b[++n]=a[i];}sum2=N*(N-1)/2;sort(b+1,b+n+1);}bool check(ll i,ll now){if(b[i]+b[now]<=X) return 0;return 1;}void work(){for(ll i=1;i<=n;i++){ll le=1,ri=n,mid;while(le+1<ri){mid=(le+ri)/2;if(check(i,mid)) ri=mid;else le=mid;}if(!check(i,ri)){if(i<=ri) sum1+=ri-1;if(i>ri) sum1+=ri;}if(check(i,ri)&&!check(i,le)){if(i<=le) sum1+=le-1;if(i>le) sum1+=le;}}sum1/=2;sum=1.0*sum1/sum2;printf("%.2lf\n",sum);}int main(){//freopen("a.in","r",stdin);init();work();return 0;}


0 0