测试20210422T1 Sample
题解引用了拉格朗日乘数,但是我不会,所以讲一个更简单的方法。
当 p p p 确定的时候,得分的期望应该是 2 × ∑ i ( p i − p i 2 ) 2\times\sum i(p_i-p_i^2) 2×∑i(pi−pi2) 。令 f ( p ) = p − p 2 f(p)=p-p^2 f(p)=p−p2 然后画出它的图像
![QQ图片20210422160054](https://img-blog.csdnimg.cn/20210422163054421.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JBMTAwRkRN,size_16,color_FFFFFF,t_70#pic_center)
设最优解为 p ∗ p^* p∗ ,那么任意 p a ∗ , p b ∗ p_a^*,p_b^* pa∗,pb∗ 一定满足 a f ′ ( p a ∗ ) = b f ′ ( p b ∗ ) af'(p_a^*)=bf'(p_b^*) af′(pa∗)=bf′(pb∗) 。这个很好理解,假设 a f ′ ( p a ∗ ) > b f ′ ( p b ∗ ) af'(p_a^*)>bf'(p_b^*) af′(pa∗)>bf′(pb∗) ,则可以让 p a ∗ + x p_a^*+x pa∗+x , p b ∗ − x , ( x → 0 ) p_b^*-x,(x\rightarrow0) pb∗−x,(x→0) ,于是 a p a ∗ ( 1 − p a ∗ ) + b p b ∗ ( 1 − p b ∗ ) < a ( p a ∗ + x ) ( 1 − ( p a ∗ + x ) ) + b ( p b ∗ − x ) ( 1 − ( p b ∗ − x ) ) ap_a^*(1-p_a^*)+bp_b^*(1-p_b^*)<a(p_a^*+x)(1-(p_a^*+x))+b(p_b^*-x)(1-(p_b^*-x)) apa∗(1−pa∗)+bpb∗(1−pb∗)<a(pa∗+x)(1−(pa∗+x))+b(pb∗−x)(1−(pb∗−x)) 显然这样 p ∗ p^* p∗ 就不是最优的了。所以画出每一个 y i = i f ′ ( p ) y_i=if'(p) yi=if′(p) 的图像
![QQ图片20210422160054](https://img-blog.csdnimg.cn/20210422163324949.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JBMTAwRkRN,size_16,color_FFFFFF,t_70#pic_center)
和图中一样,我们现在只需要找到一个蓝线
l
:
y
=
C
l:y=C
l:y=C ,使得联立
y
i
=
i
f
′
(
p
)
y_i=if'(p)
yi=if′(p) 与
y
=
C
y=C
y=C 后
∑
p
i
=
1
\sum p_i=1
∑pi=1 。这个问题直接二分就可以了。
这样我们就能求出
C
C
C,考虑如何求答案,因为
p
i
=
i
−
C
2
i
p_i=\frac{i-C}{2i}
pi=2ii−C ,所以答案的可以写成
∑
i
>
C
i
2
−
C
2
2
i
\sum_{i>C}\frac{i}{2}-\frac{C^2}{2i}
∑i>C2i−2iC2 。所以求出
C
C
C 后,我们可以直接计算出答案。总时间复杂度
O
(
T
log
n
)
O(T\log n)
O(Tlogn) 。
写代码的时候注意精度问题,别二分进死循环了2333
#include <bits/stdc++.h>
#define N 1000006
using namespace std;
const double eps=1e-10;
const int maxn=1e6;
double n,inv[N],sum[N];
int nn;
void get_pos(double &mid){
double l=0,r=n,now;
while(r-l>eps){
mid=(r+l)*0.5;
if(mid==l||mid==r) break;
now=n-floor(mid)-mid*(inv[nn]-inv[(int)floor(mid)]);
if(now>2) l=mid;
else r=mid;
}
}
void work(){
cin>>n; nn=n;
if(n<=1){ printf("%.14lf\n",(double)0); return; }
if(n==2){ printf("%.14lf\n",(double)1.5); return; }
double pos=(n-2.0)/inv[nn],ans=0,o=0.5;
get_pos(pos);
ans=o*(sum[nn]-sum[(int)floor(pos)]-pos*pos*(inv[nn]-inv[(int)floor(pos)]));
printf("%.14lf\n",ans);
}
void init(){
for(double i=1;i<=maxn;i++)
inv[(int)i]=inv[(int)i-1]+(double)1.0/i,
sum[(int)i]=sum[(int)i-1]+i;
}
int main(){
init();
int T; cin>>T;
while(T--){ work(); }
}
听蒋神讲完题解做法后发现,我这个做法就是底层逻辑2333,(所以我前两天的拉格朗日乘子还是白学了giao