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)
p∗q(−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(1≤n≤1,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
<
l
r2<l
r2<l,那么也不用考虑左端点,他的贡献是0;
③最后考虑第二条线右端点
r
2
>
r
r2>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/(n∗i)
枚举第一个区间,对于情况①,我们可以算出其对当前区间的贡献的概率为
(
i
−
j
+
1
)
/
n
(i-j+1)/n
(i−j+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)/(2∗n)
所有的情况③的贡献值是
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;
}