[hdu6574]Rng

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)

分数:2300,推算过程有点困难。

Problem Description
Avin is studying how to synthesize data. Given an integer n n n, he constructs an interval using the following method: he first generates a integer r r r between 1 1 1 and n n n (both inclusive) uniform-randomly, and then generates another integer l l l between 1 1 1 and r r r (both inclusive) uniform-randomly. The interval [ l , r ] [l, r] [l,r] is then constructed. Avin has constructed two intervals using the method above. He asks you what the probability that two intervals intersect is. You should print p ∗ q ( − 1 ) ( M O D   1000000007 ) p* q(−1)(MOD \ 1000000007) pq(1)(MOD 1000000007), while pq denoting the probability.

Input
Just one line contains the number n ( 1 ≤ n ≤ 1 , 000 , 000 ) n (1 ≤ n ≤ 1, 000, 000) n(1n1,000,000).

Output
Print the answer.

Sample Input

1
2

Sample Output

1
750000006

题意:
给定一个长度为n的线段,你生成一个区间的方式是先从 [ 1 , n ] [1,n] [1,n]中随机一个右端点 r r r,然后再从 [ 1 , r ] [1,r] [1,r]中随机生成一个左端点 l l l,端点都是整点。问,依照这种方式生成两个区间,这两个区间相交的概率是多少。

题解:
tips:这题其实询问次数很少。
首先我们先考虑一个区间的生成概率,生成一个右端点的概率是 1 / n 1/n 1/n,对于当前的右端点 r r r我们可以计算出他的左端点概率为 1 / r 1/r 1/r,然后我们考虑第二个区间与其相交的概率。
①如果第二条直线的右端点 r 2 r2 r2位于 [ l , r ] [l,r] [l,r]以内,那么他的左端点显然可以不用考虑了;
②如果第二条直线的右端点 r 2 &lt; l r2&lt;l r2<l,那么也不用考虑左端点,他的贡献是0;
③最后考虑第二条线右端点 r 2 &gt; r r2&gt;r r2>r的情况,那么他们相交的概率就是 r / r 2 r/r2 r/r2

先考虑朴素的 O ( n 2 ) O(n^2) O(n2)做法,枚举右端点 i i i和左端点 j j j.
设第一个区间为 [ j , i ] [j,i] [j,i],他对答案贡献概率为 1 / ( n ∗ i ) 1/(n*i) 1/(ni)
枚举第一个区间,对于情况①,我们可以算出其对当前区间的贡献的概率为 ( i − j + 1 ) / n (i-j+1)/n (ij+1)/n
对于情况③,我们可以算出右端点为 r 2 r2 r2的区间对当前区间的贡献概率为 ( 1 / n ) ∗ ( i / r 2 ) = ( i / n ) ∗ ( 1 / r 2 ) (1/n)*(i/r2)=(i/n)*(1/r2) (1/n)(i/r2)=(i/n)(1/r2) ( r 2 ∈ [ i + 1 , n ] ) (r2\in[i+1,n]) (r2[i+1,n])
我们可以先维护一个 ∑ i = 1 n ( 1 / i ) \sum^n_{i=1} (1/i) i=1n(1/i)的前缀和。来达到快速计算所有情况③的和的目的。

最后考虑将 O ( n 2 ) O(n^2) O(n2)方法做成 O ( n ) O(n) O(n)线性递推。
我们发现所有的贡献中只有计算情况1的时候需要用到 j j j,由于 j ∈ [ 1 , i ] j \in [1,i] j[1,i] 那么其实对于我们枚举的右端点 i i i来说,所有情况①的贡献值是 i ∗ ( i + 1 ) / ( 2 ∗ n ) i*(i+1)/(2*n) i(i+1)/(2n)
所有的情况③的贡献值是 i ∗ ( i / n ) ∗ ∑ r 2 = i + 1 n ( 1 / r 2 ) i*(i/n)*\sum^n_{r2=i+1}(1/r2) i(i/n)r2=i+1n(1/r2)
直接计算即可。时间复杂度是 O ( n l o g ( M O D ) ) O(nlog(MOD)) O(nlog(MOD))

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007LL
#define pa pair<ll,ll>
using namespace std;
ll n,ans,sum;
ll fp(ll x,ll y){
    if(y==0)return 1LL;
    ll temp=fp(x,y>>1);
    if(y&1)return (((temp*temp)%MOD)*x)%MOD;
    else return (temp*temp)%MOD;
}
ll rev(ll x){
    return fp(x,MOD-2);
}
ll calc(ll x){
    return x*(x+1)/2;
}
bool in(ll l,ll r,ll a,ll b){
    if(a>r||b<l)return 0;
    return 1;
}
ll revx[1000004];
ll get(ll l,ll r){
    return (revx[r]-revx[l-1]+MOD)%MOD;
}
void prework(){
    revx[1]=1;
    revx[0]=0;
    for(ll i=2;i<=1000001;i++){
        revx[i]=((MOD-MOD/i)*revx[MOD%i])%MOD;
    }
    for(ll i=2;i<=1000001;i++){
        revx[i]+=revx[i-1];
        revx[i]%=MOD;
    }
}
int w33ha(){
    ans=0;
    for(ll i=1;i<=n;i++){
        ll g=rev(n*i),p=get(n,n);
        ll now1=(g*p)%MOD;
        now1*=(i+1)*i/2;now1%=MOD;
        ll now2=(g*p)%MOD;
        now2*=get(i+1,n);now2%=MOD;
        now2*=i;now2%=MOD;
        now2*=i;now2%=MOD;
        ans+=now1;ans%=MOD;
        ans+=now2;ans%=MOD;
    }
    printf("%lld\n",ans);
    return 0;
}
int main(){
    prework();
    while(scanf("%lld",&n)!=EOF)w33ha();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值