作爲一名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;
}