作为一名osu!玩家,这道题成功吸引到了我。。。
题意
长度为n的序列,给出每一个数字可能为1的概率
将玩家完成一张地图的01串中所有的0删去,则这个串可能会断裂成若干段连续的1。对于一段长度为1011101110
,则删除所有0后得到的是“1”“111”和“111”
。因此这个玩家的得分为(1+1+1)+(9+3+1)+(9+3+1)=29
。
题解
这是出题人的题解
下面简述此题解内容。
分值的计算为
将其分为三部分分别计算期望:
复杂度
考虑第
复杂度
由于出现了平方,计算
定义两个数列
对于
对于
复杂度
用线段树维护信息与查询
维护
维护
若
故记录区间左右端点的
维护
这是一个线性变换,表示矩阵为
所以拿
这道题没有区间修改不用打标记,每个区间直接记录矩阵,由于矩阵乘法的结合律,可以用线段树维护区间的矩阵乘积。但是直接这么写常数太大。
观察
可以看到一个矩阵我们只需记录四个值即可,大大减小了常数。
复杂度
这道题还有个简化版本,在BZOJ4318,给出PO姐的题解
代码
/// by ztx
/// blog.csdn.net/hzoi_ztx
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v) for(i=v.begin();i!=v.end();i++)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
#define kN 500010LL
#define kT 2000010LL
#define M ((L+R)/2)
#define l(o) (o<<1)
#define r(o) (o<<1|1)
#define left l(o),L,M
#define right r(o),M+1,R
struct mat { lf x[4]; };
inline mat Mul(const mat&a,const mat&b) {
return (mat){a.x[0]*b.x[0],a.x[0]*b.x[1]+a.x[1],a.x[2]*b.x[0]+b.x[2],a.x[2]*b.x[1]+a.x[3]+b.x[3]};
}
inline void One(mat&a) {
a.x[0] = 1.0, a.x[1] = a.x[2] = a.x[3] = 0;
}
inline lf Ans(const mat&a) {
return a.x[3];
// (0,0,1) * (a b 0) = (c,d,1)
// (0 1 0) ^
// (c d 1)
}
int n, ql, qr;
lf a[kN], qw, qa0, qa1, qra;
mat qa2;
lf s0[kT], s1[kT], la[kT], ra[kT];
mat t[kT];
void update(int o) {
la[o] = la[l(o)], ra[o] = ra[r(o)];
s0[o] = s0[l(o)]+s0[r(o)]-ra[l(o)]*la[r(o)];
s1[o] = s1[l(o)]+s1[r(o)];
t[o] = Mul(t[l(o)],t[r(o)]);
}
void Build(int o=1, int L=1, int R=n) {
if (L == R) {
t[o].x[0] = t[o].x[2] = t[o].x[3] = a[L], t[o].x[1] = a[L]*2;
la[o] = ra[o] = s0[o] = s1[o] = a[L];
return ;
}
Build(left), Build(right);
update(o);
}
void Modify(int o=1, int L=1, int R=n) {
if (L == R) {
a[L] = qw;
t[o].x[0] = t[o].x[2] = t[o].x[3] = qw, t[o].x[1] = qw*2;
la[o] = ra[o] = s0[o] = s1[o] = qw;
return ;
}
if (ql <= M) Modify(left);
else Modify(right);
update(o);
}
void Query(int o=1, int L=1, int R=n) {
if (ql<=L && R<=qr) {
qa0 += s0[o]-qra*la[o], qra = ra[o];
qa1 += s1[o];
qa2 = Mul(qa2,t[o]);
return ;
}
if (ql <= M) Query(left);
if (qr > M) Query(right);
}
#undef r
#define r(x) read(x)
int main() {
int m, i, ope;
r(n), r(m);
Rep (i,1,n) scanf("%lf", &a[i]);
Build();
while (m --> 0) {
r(ope);
if (ope) r(ql), scanf("%lf", &qw), Modify();
else r(ql), r(qr), qa0=qa1=qra=0, One(qa2), Query(), printf("%.2f\n", qa0+qa1+Ans(qa2));
}
END: getchar(), getchar();
return 0;
}