1. 程式人生 > >5928. 【NOIP2018模擬10.26】蘋果

5928. 【NOIP2018模擬10.26】蘋果

題目

對區間 [ 1 , 2 n ] [1,2^n] 建線段樹。線段樹中每個區間都有它自己的深度。
眾所周知, 一個區間 [

L , R ] [L,R] 可以拆成log個區間。
S ( L ,
R ) S(L,R)
的期望。
對於一個區間 [ L , R ]
[L,R]
S ( L , R ) S(L,R) 表示 l o g log 個區間中包含L的那個區間的深度+ l o g log 個區間中包含R的那個區間的深度。如果只有1個區間,那麼那個區間的深度算2次。

正解

40分:式子很容易就寫出來了。
A n s = 1 C 2 n 2 i = 1 n d e p [ i ] ( s i z e [ i   x o r   1 ] ) + [ d e p [ i ] ( 2 n R [ i ] + 1 ) ] [ i ] + [ d e p [ i ] ( s i z e [ i   x o r   1 ] ) + d e p [ i ] L [ i ] ] [ i ] Ans=\frac{1}{C_{2^n}^2}\sum_{i=1}^n dep[i]*(size[i\ xor\ 1])+[dep[i]*(2^n-R[i]+1)]*[i為奇數]+[dep[i]*(size[i\ xor\ 1])+dep[i]*L[i]]*[i為偶數]
100分:找規律。或者優化40分的式子。
找規律:對於所有的 [ L , R ] [L,R] 數出每個區間遍歷的次數。
可以得出結論:深度為i的區間總共被遍歷了 2 i 1 ( 2 n + 2 ) 2^{i-1}(2^n+2) 次。
所以 A n s = i = 1 n i 2 i 1 ( 2 n + 2 ) = i = 1 n i 2 i ( 2 n 1 + 1 ) Ans=\sum_{i=1}^n i*2^{i-1}(2^n+2)=\sum_{i=1}^n i*2^i(2^{n-1}+1)
一個等差比數列。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define mo 1000000007
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL ans,w,w1;
LL m1,m2,m3,n;
LL calc(LL x){return (x*(x+1)%mo)*500000004%mo;}
LL ksm(LL x,LL y){
	LL rs=1;
	for(;y;y>>=1,x=(x*x)%mo)if(y&1)rs=(rs*x)%mo;
	return rs;
}
int main(){
	scanf("%lld",&n);
	m1=ksm(2,n-1);
	m2=m1*2%mo;
	m3=m2*2%mo;
	ans=(ans+(n%mo)*m3%mo-2+mo)%mo;
	w1=(4*(m1-1))%mo;
	ans=(ans-w1+mo)%mo;
	w1=(m1+1)%mo;
	ans=(ans*w1)%mo;
	w=calc(m2);
	ans=(ans*ksm(w,mo-2))%mo;
	printf("%lld",ans);
	return 0;
}