jzoj 5837.【省选&A组模拟2018.8.21】Omeed 线段树

本文介绍了一种利用线段树解决概率与组合问题的方法,通过递归定义和转移方程来计算特定区间内的期望值。该方法适用于解决涉及概率更新和区间查询的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input
3
3 5 1 2 2 3
1 2
0 2
2 2
1 1 2
1 1 3
0 2 3 7
0 3 2 9
1 1 3

Sample Output
499122179
748683273
966554063

Data Constraint
这里写图片描述
Hint
这里写图片描述
以下为样例解释:
这里写图片描述

分析:
基础分的期望非常显然,即

Basicscore=Ai=lrpiBasicscore=A∗∑i=lrpi

fificombo(i)combo(i)的期望,连击分期望就是
Comboscore=Bi=lrpi(fi1+1)Comboscore=B∗∑i=lrpi∗(fi−1+1)

显然这次要是11才能得到combo分,分数值显然就是i1i−1的期望+1+1了。
考虑怎样求fifi,显然可以从i1i−1转移,考虑当前为是否为11,有
fi=pi(fi1+1)+(1pi)fi1t

tt就是题目中的那个t,就等于tatbtatb
化简上面的式子,得
fi=(pi+tpit)fi1+pifi=(pi+t−pi∗t)fi−1+pi

显然是一个关于fi1fi−1的一次函数,那么ComboscoreComboscore也是一个一次函数。

我们考虑线段树维护区间[L,R][L,R]55个值,分别为sump,k,b,sumk,sumb,表示概率和(解决基本分),fR=kfL1+bfR=k∗fL−1+bComboscore(l,r)=sumkfL1+sumbComboscore(l,r)=sumk∗fL−1+sumb
考虑合并两个区间,因为右区间的fL1fL−1就是左区间的fRfR,这就是我们维护这两个东西的原因。具体转移可以手推,程序也有。
程序常数较大,最后我全部intint加强制类型转换卡过去了。
我的程序就算慢得爆炸,常数大得飞起,也不会开读入优化

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#define LL long long 

const int maxn=5e5+7;
const LL mod=998244353;

using namespace std;

int n,test,op,l,r;
int A,B,T,ta,tb,x,y;
int pi[maxn];

struct node{
    int sump,k,b,sumk,sumb;
}t[maxn*4];

int power(int x,int y)
{
    if (y==1) return x;
    int c=power(x,y/2);
    c=(LL)c*(LL)c%mod;
    if (y%2) c=(LL)c*(LL)x%mod;
    return c;
}

node neww(int p)
{
    node z;
    z.sump=p;
    z.k=((LL)p+(LL)T+mod-(LL)p*(LL)T%mod)%mod;
    z.b=p;
    z.sumk=p;
    z.sumb=p;
    return z;
}

node merge(node x,node y)
{
    node z;
    z.sump=((LL)x.sump+(LL)y.sump)%mod;
    z.k=((LL)x.k*(LL)y.k)%mod;
    z.b=((LL)y.k*(LL)x.b%mod+(LL)y.b)%mod;
    z.sumk=((LL)y.sumk*(LL)x.k%mod+(LL)x.sumk)%mod;
    z.sumb=((LL)y.sumk*(LL)x.b%mod+(LL)x.sumb+(LL)y.sumb)%mod;
    return z;
}

void build(int p,int l,int r)
{
    if (l==r)
    {
        t[p]=neww(pi[l]);
        return;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p]=merge(t[p*2],t[p*2+1]);
}

void change(int p,int l,int r,int x,LL k)
{
    if (l==r)
    {
        t[p]=neww(k);
        return;
    }
    int mid=(l+r)/2;
    if (x<=mid) change(p*2,l,mid,x,k);
           else change(p*2+1,mid+1,r,x,k);
    t[p]=merge(t[p*2],t[p*2+1]);
}

node query(int p,int l,int r,int x,int y)
{
    if ((l==x) && (r==y)) return t[p];
    int mid=(l+r)/2;
    if (y<=mid) return query(p*2,l,mid,x,y);
    else if (x>mid) return query(p*2+1,mid+1,r,x,y);
    else
    {
        return merge(query(p*2,l,mid,x,mid),query(p*2+1,mid+1,r,mid+1,y));
    }
}

int main()
{
    freopen("omeed.in","r",stdin);
    freopen("omeed.out","w",stdout);
    scanf("%d",&n);
    scanf("%d%d%d%d%d%d",&n,&test,&ta,&tb,&A,&B);   
    T=(LL)ta*(LL)power(tb,mod-2)%mod;
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        pi[i]=(LL)x*(LL)power(y,mod-2)%mod;
    }       
    build(1,1,n);
    for (int i=1;i<=test;i++)
    {
        scanf("%d",&op);
        if (op==0)
        {
            scanf("%d%d%d",&l,&x,&y);
            LL p=(LL)x*(LL)power(y,mod-2)%mod;
            change(1,1,n,l,p);
        }
        else
        {
            scanf("%d%d",&l,&r);
            node d=query(1,1,n,l,r);
            LL ans=((LL)A*(LL)d.sump%mod+(LL)B*(LL)d.sumb%mod)%mod;
            printf("%lld\n",ans);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值