高一上六月下旬日记

6.27

闲话

  • 下午返校了,在校门口取新高一的校服。试穿时用力太大不小心将左眼镜腿掰折了一截,因为着急进校,就凑活用了。
  • 进校后回 \(1506\) 发现我的行李从上铺搬到了下铺,摊在床上,稍微值点钱的东西都没了,包括但不限于肥皂、洗衣粉、两大袋零食、指甲剪、风油精、剪刀、湿巾、锁加两个钥匙、鞋套、花露水、鞋垫、水杯、雨伞、卫生纸。
  • 以为是单独取食堂办饭卡,但失败了,遇到其他奥赛的一问才知道取找奥赛教练要饭卡,遂回机房取饭卡。
  • 机房 \(ftp\) 开开了,【数据删除】没动,@wkh2008 称其是“钓鱼执法”。
  • 晚上 \(field\) 说了下作息时间表,还说要给我们打印一份贴墙上,但直到放学也没看见作息时间表。
  • \(field\) 称等高中的分完班后我们就搬到本部去,让我们做好心理准备。
  • \(field\) 在机房收手机放到了“机柜”(机房的柜子),说把手机放到“宿柜”(宿舍的柜子)容易被查。
  • 晚休一开始是数奥教练查宿,“信息的那几个快点啊”,后面没有宿管来。

做题纪要

luogu P10495 阶乘分解

  • 筛出 \(1 \sim n\) 的所有素数 \(\{ p \}\) ,设其共有 \(m\) 个,则 \(n!=\prod\limits_{i=1}^{m}p_{i}^{\sum\limits_{j=1}^{\left\lfloor \log_{p_{i}} n \right\rfloor} \left\lfloor \frac{n}{p_{i}^{j}} \right\rfloor}\)

    点击查看代码
    int prime[1000010],len=0;
    bool vis[1000010];
    void isprime(int n)
    {
        memset(vis,false,sizeof(vis));
        for(int i=2;i<=n;i++)
        {
            if(vis[i]==false)
            {
                len++;
                prime[len]=i;
            }
            for(int j=1;j<=len&&i*prime[j]<=n;j++)
            {
                vis[i*prime[j]]=true;
                if(i%prime[j]==0)
                {
                    break;
                }
            }
        }
    }
    int main()
    {
        int n,c,i,j;
        cin>>n;
        isprime(n);
        for(i=1;i<=len;i++)
        {
            c=0;
            for(j=1;pow(prime[i],j)<=n;j++)
            {
                c+=n/pow(prime[i],j);
            }
            cout<<prime[i]<<" "<<c<<endl;
        }
        return 0;
    }
    

SP2916 GSS5 - Can you answer these queries V

  • \(pre_{l,r}\) 表示 \([l,r]\) 的最大左子段和, \(suf_{l,r}\) 表示 \([l,r]\) 的最大右子段和, \(ans_{l,r}\) 表示 \([l,r]\) 的最大右子段和, \(sum_{l,r}\) 表示 \([l,r]\) 的区间和。

  • 大力分讨。

    • \([x_{1},y_{1}]\)\([x_{2},y_{2}]\) 不相交时,有 \(suf_{x_{1},y_{1}}+sum_{y_{1}+1,x_{2}-1}+pre_{x_{2},y_{2}}\) 即为所求,为保证区间存在故 \(suf_{x_{1},y_{1}}+sum_{y_{1},x_{2}}+pre_{x_{2},y_{2}}-a_{y_{1}}-a_{x_{2}}\) 即为所求。
    • \([x_{1},y_{1}]\)\([x_{2},y_{2}]\) 相交时,有 \(\max \{ suf_{x_{1},x_{2}}+pre_{x_{2}+1,y_{2}},ans_{x_{2},y_{1}},suf_{x_{1},y_{1}}+pre_{y_{1}+1,y_{2}} \}\) 即为所求,为保证区间存在故 \(\max \{ suf_{x_{1},x_{2}}+pre_{x_{2},y_{2}}-a_{x_{2}},ans_{x_{2},y_{1}},suf_{x_{1},y_{1}}+pre_{y_{1},y_{2}}-a_{y_{1}} \}\) 即为所求。
    点击查看代码
    int a[10010];
    struct SMT
    {
        struct SegmentTree
        {
            int l,r,sum,suf,pre,ans;
        }tree[40010];
        int lson(int x)
        {
            return x*2;
        }
        int rson(int x)
        {
            return x*2+1;
        }
        void pushup(int rt)
        {
            tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
            tree[rt].pre=max(tree[lson(rt)].pre,tree[lson(rt)].sum+tree[rson(rt)].pre);
            tree[rt].suf=max(tree[rson(rt)].suf,tree[rson(rt)].sum+tree[lson(rt)].suf);
            tree[rt].ans=max(tree[lson(rt)].suf+tree[rson(rt)].pre,max(tree[lson(rt)].ans,tree[rson(rt)].ans));
        }
        void build(int rt,int l,int r)
        {
            tree[rt].l=l;
            tree[rt].r=r;
            if(l==r)
            {
                tree[rt].sum=tree[rt].suf=tree[rt].pre=tree[rt].ans=a[l];
                return;
            }
            int mid=(l+r)/2;
            build(lson(rt),l,mid);
            build(rson(rt),mid+1,r);
            pushup(rt);
        }
        SegmentTree query(int rt,int x,int y)
        {
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                return tree[rt];
            }
            int mid=(tree[rt].l+tree[rt].r)/2;
            if(y<=mid)
            {
                return query(lson(rt),x,y);
            }
            else
            {
                if(x>mid)
                {
                    return query(rson(rt),x,y);
                }
                else
                {
                    SegmentTree p=query(lson(rt),x,y),q=query(rson(rt),x,y),num;
                    num.sum=p.sum+q.sum;
                    num.pre=max(p.pre,p.sum+q.pre);
                    num.suf=max(q.suf,q.sum+p.suf);
                    num.ans=max(p.suf+q.pre,max(p.ans,q.ans));
                    return num;
                }
            }
        }
    }T;
    int main()
    {
        int t,n,m,x1,y1,x2,y2,i,j;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n;
            for(j=1;j<=n;j++)
            {
                cin>>a[j];
            }
            T.build(1,1,n);
            cin>>m;
            for(j=1;j<=m;j++)
            {
                cin>>x1>>y1>>x2>>y2;
                if(y1<x2)
                {
                    cout<<T.query(1,x1,y1).suf+T.query(1,y1,x2).sum+T.query(1,x2,y2).pre-a[y1]-a[x2]<<endl;
                }
                else
                {
                    cout<<max(T.query(1,x1,x2).suf+T.query(1,x2,y2).pre-a[x2],max(T.query(1,x2,y1).ans,T.query(1,x1,y1).suf+T.query(1,y1,y2).pre-a[y1]))<<endl;;
                }
            }
        }
        return 0;
    }
    

6.28

闲话

  • 早上跑操本来在 \(23429\) 班后面跑,我以为站位和初中的一样(竖向),遂直接站到了操场最右侧,到那里的时候一个人也没有,然后数奥教练也是这么认为的,也跟了过来,故没有追究班号的问题。数奥的可能还因此找错了位置,没有一个人来跑操。实际上,高一 \(4\) 部站位是横向的,进跑道也是横向进,把我们看懵了。跑道上统一在外侧没有被拆掉跑道的部分跑,但我们以前都是靠里侧被拆掉跑道的部分跑的,离谱。
  • 上午 \(miaomiao\) 给我们放了容斥原理和概率期望 \(DP\) 的视频; \(miaomiao\) 让我们换到 h.普及oj(一开始是全部搬的GXYZOJ) 上。结果没有 \(MLE\) 的评测信息,全部爆的是 \(RE\) ,和 \(Accoders\) 一个尿性;CF域写的是 \(RMJ\) ,貌似还是借的Hydro;luogu域 \(miaomiao\) 称题太多了,他懒得搬了,让我们需要啥再让他搬。还称“这是你们唯一一次改名字的机会啊”,但他是不知道以前我们经常用 readonly="" 改用户名吗?
  • 中午回宿舍后发现电话还是没通。
  • 晚上 \(miaomiao\) 突然问我们 \(LCA\) 会几种写法,问概率期望专题的题是不是有点难,说让我们趁着高中没放假这几天抓紧赶进度,暑假就和他们一起打模拟赛了。
  • 晚休数奥教练和 \(miaomiao\) 来查宿;数奥教练说了下明天跑操的站位;我和 \(miaomiao\) 说了下电话的问题,他说跟学校里问问; \(miaomiao\) 问了问我们进度,“明天再给半天还够吗”,“反正你们现在啥没学就赶紧补啊”。

做题纪要

luogu P4316 绿豆蛙的归宿

  • \(f_{x}\) 表示从 \(x\) 走到终点所经过的路径的期望长度,状态转移方程为 \(f_{x}=\frac{1}{out_{x}} \times \sum\limits_{(x,y,z) \in E}(f_{y}+z)\) ,边界为 \(f_{n}=0\)

  • 建反图跑拓扑即可。

    点击查看代码
    struct node
    {
        int nxt,to,w;
    }e[200010];
    int head[200010],din[200010],dout[200010],cnt=0;
    double f[200010];
    void add(int u,int v,int w)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        e[cnt].w=w;
        head[u]=cnt;
    }
    void top_sort(int n)
    {
        queue<int>q;
        int x,i;
        for(i=1;i<=n;i++)
        {
            if(din[i]==0)
            {
                q.push(i);
            }
        }
        while(q.empty()==0)
        {
            x=q.front();
            q.pop();
            for(i=head[x];i!=0;i=e[i].nxt)
            {
                din[e[i].to]--;
                f[e[i].to]+=(f[x]+1.0*e[i].w)/dout[e[i].to];
                if(din[e[i].to]==0)
                {
                    q.push(e[i].to);
                }
            }
        }
    }
    int main()
    {
        int n,m,u,v,w,i;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            cin>>u>>v>>w;
            add(v,u,w);
            din[u]++;
            dout[u]++;
        }
        top_sort(n);
        printf("%.2lf\n",f[1]);
        return 0;
    }
    

CF451E Devu and Flowers

  • 多重集组合数板子。

  • 枚举集合后卢卡斯求解即可。

    点击查看代码
    const ll p=1000000007;
    ll inv[25],jc_inv[25],a[25];
    ll qpow(ll a,ll b,ll p)
    {
        ll ans=1;
        while(b)
        {
            if(b&1)
            {
                ans=ans*a%p;
            }
            b>>=1;
            a=a*a%p;
        }
        return ans;
    }
    ll C(ll n,ll m,ll p)
    {
        if(n>=m&&n>=0&&m>=0)
        {
            ll ans=jc_inv[m];
            for(ll i=n-m+1;i<=n;i++)
            {
                ans=ans*i%p;
            }
            return ans;
        }
        else
        {
            return 0;
        }
    }
    ll lucas(ll n,ll m,ll p)
    {
        return m?C(n%p,m%p,p)*lucas(n/p,m/p,p)%p:1;
    }
    int main()
    {
        ll n,m,ans=0,sum,num,i,s;
        cin>>n>>m;
        jc_inv[0]=1;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
            inv[i]=qpow(i,p-2,p);
            jc_inv[i]=jc_inv[i-1]*inv[i]%p;
        }
        for(s=0;s<=(1<<n)-1;s++)
        {
            sum=0;
            num=0;
            for(i=0;i<=n-1;i++)
            {
                if((s>>i)&1)
                {
                    sum+=(a[i+1]+1);
                    num++;
                }
            }
            ans=(ans+((num%2==0)?1:-1)*lucas(n+m-1-sum,n-1,p)+p)%p;
        }
        cout<<ans<<endl;
        return 0;
    }
    

UVA12369 Cards

  • 本题中的得到是指目前的牌中包含所要求的牌,而不是目前的牌中恰好是所要求的牌。

  • \(f_{a,b,c,d,x,y}\) 表示已经抽了 \(a\) 张黑桃, \(b\) 张红桃, \(c\) 张梅花, \(d\) 张方块,大王/小王的使用状态为 \(x/y\) 时的期望张数。具体地, \(x/y=0 \sim 3\) 分别表示大王/小王视为黑桃、红桃、梅花、方块, \(x/y=4\) 表示未使用大王/小王。

  • 状态转移方程为 \(f_{a,b,c,d,x,y}=1+\frac{13-a}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a+1,b,c,d,x,y}+\frac{13-b}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b+1,c,d,x,y}+\frac{13-c}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b,c+1,d,x,y}+\frac{13-d}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b,c,d+1,x,y}+\frac{[x=4]}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times \min\limits_{x'=0}^{3} \{ f_{a,b,c,d,x',y} \}+\frac{[y=4]}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times \min\limits_{y'=0}^{3} \{ f_{a,b,c,d,x,y'} \}\) ,需要注意边界处理。

  • 记忆化搜索时维护即可。

  • 最终,有 \(f_{0,0,0,0,4,4}\) 即为所求。

    点击查看代码
    int A,B,C,D;
    double f[20][20][20][20][8][8];
    bool vis[20][20][20][20][8][8];
    double dfs(int a,int b,int c,int d,int x,int y)
    {
        if(vis[a][b][c][d][x][y]==false)
        {
            vis[a][b][c][d][x][y]=true;
            int sum=a+b+c+d+(x!=4)+(y!=4);
            double minn;
            if(a>13||b>13||c>13||d>13||sum>54)
            {
                f[a][b][c][d][x][y]=0x7f7f7f7f;
            }
            else
            {
                if(a+(x==0)+(y==0)>=A&&b+(x==1)+(y==1)>=B&&c+(x==2)+(y==2)>=C&&d+(x==3)+(y==3)>=D)
                {
                    f[a][b][c][d][x][y]=0;
                }
                else
                {
                    f[a][b][c][d][x][y]=1+1.0*(13-a)/(54-sum)*dfs(a+1,b,c,d,x,y)
                                        +1.0*(13-b)/(54-sum)*dfs(a,b+1,c,d,x,y)
                                        +1.0*(13-c)/(54-sum)*dfs(a,b,c+1,d,x,y)
                                        +1.0*(13-d)/(54-sum)*dfs(a,b,c,d+1,x,y);
                    if(x==4)
                    {
                        minn=0x7f7f7f7f;
                        for(int i=0;i<=3;i++)
                        {
                            minn=min(minn,dfs(a,b,c,d,i,y));
                        }
                        f[a][b][c][d][x][y]+=1.0/(54-sum)*minn;
                    }
                    if(y==4)
                    {
                        minn=0x7f7f7f7f;
                        for(int i=0;i<=3;i++)
                        {
                            minn=min(minn,dfs(a,b,c,d,x,i));
                        }
                        f[a][b][c][d][x][y]+=1.0/(54-sum)*minn;
                    }
                }
            }
        }
        return f[a][b][c][d][x][y];
    }
    int main()
    {
        int t,i;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>A>>B>>C>>D;
            memset(f,0,sizeof(f));
            memset(vis,0,sizeof(vis));
            double ans=dfs(0,0,0,0,4,4);
            cout<<"Case "<<i<<": ";
            if(ans<=54)
            {
                printf("%.3lf\n",ans);
            }
            else
            {
                cout<<"-1.000"<<endl;
            }
        }
        return 0;
    }
    

luogu P10504 守卫者的挑战

  • 地图残片的大小为 \(1\) 可以转化为容量为 \(-1\) 的包包,而不用去担心怎么分配的问题。

  • "只需要完成所有 \(n\) 项挑战后背包容量足够容纳地图残片即可"这个条件很重要。

  • \(f_{i,j,k}\) 表示当前进行了 \(i\) 次挑战,成功了 \(j\) 次,目前背包剩余容量为 \(k\) 时的概率,状态转移方程为 \(f_{i,j,k}=(1-p_{i}\%) \times f_{i-1,j,k}+p_{i} \% \times f_{i-1,j-1,k-a_{i}}\) ,边界为 \(f_{0,0,k}=1\) 。特别地,对于剩余容量 \(\ge n\) 的情况均可看做剩余容量 \(=n\) 的情况。

  • 由于背包容量 \(\in [-n,n]\) ,将数组整体向右平移即可。

  • 最终,有 \(\sum\limits_{i=l}^{n}\sum\limits_{j=0}^{n}f_{n,i,j}\) 即为所求。

    点击查看代码
    int a[202],p[202];
    double f[202][202][402];
    int main()
    {
        int n,l,k,i,j,h;
        double ans=0;
        cin>>n>>l>>k;
        for(i=1;i<=n;i++)
        {
            cin>>p[i];
        }
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        f[0][0][200+min(k,n)]=1;
        for(i=0;i<=n;i++)
        {
            for(j=0;j<=i;j++)
            {
                for(h=200-n;h<=200+n;h++)
                {
                    f[i+1][j][h]+=(1.0-p[i+1]/100.0)*f[i][j][h];
                    f[i+1][j+1][min(200+n,h+a[i+1])]+=p[i+1]/100.0*f[i][j][h];
                }
            }
        }
        for(i=l;i<=n;i++)
        {
            for(j=200;j<=200+n;j++)
            {
                ans+=f[n][i][j];
            }
        }
        printf("%.6lf\n",ans);
        return 0;
    }
    

LightOJ 1248.Dice (III)

  • \(f_{i}\) 表示已经看到 \(i\) 面不同的面时还需要的期望次数,有 \(f_{i}=1+\frac{i}{n} \times f_{i}+\frac{n-i}{n} \times f_{i+1}\) ,移项得到状态转移方程 \(f_{i}=f_{i+1}+\frac{n}{n-i}\) ,边界为 \(f_{n}=0\)

  • 最终,有 \(f_{0}\) 即为所求。

    点击查看代码
    double f[100010];
    int main()
    {
        int t,n,i,j;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n;
            f[n]=0;
            for(j=n-1;j>=0;j--)
            {
                f[j]=f[j+1]+1.0*n/(n-j);
            }
            printf("Case %d: %.8lf\n",i,f[0]);
        }
        return 0;
    }
    

LightOJ 1030.Discovering Gold

  • \(a_{i}\) 表示第 \(i\) 个格子的黄金数量, \(f_{i}\) 表示当前在第 \(i\) 个格子,到达第 \(n\) 个格子的期望黄金数量,状态转移方程为 \(f_{i}=a_{i}+\sum\limits_{j=i+1}^{\min(i+6,n)}\frac{f_{i+j}}{\min(6,n-i)}\)

  • 最终,有 \(f_{1}\) 即为所求。

    点击查看代码
    int a[110];
    double f[110];
    int main()
    {
        int t,n,i,j,k;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n;
            for(j=1;j<=n;j++)
            {
                cin>>a[j];
            }
            for(j=n;j>=1;j--)
            {
                f[j]=a[j];
                for(k=j+1;k<=min(j+6,n);k++)
                {
                    f[j]+=f[k]/(1.0*min(6,n-j));
                }
            }
            printf("Case %d: %.8lf\n",i,f[1]);
        }
        return 0;
    }
    

CF453A Little Pony and Expected Maximum

  • 设掷 \(n\) 次骰子后的最大值为 \(k\) ,则方案数为 \(k^{n}-(k+1)^{n}\)

  • 最终,有 \(\sum\limits_{i=1}^{m}\dfrac{(i^{n}-(i-1)^{n})}{m^{n}} \times i=\sum\limits_{i=1}^{m}((\dfrac{i}{m})^{n}-(\dfrac{i-1}{m})^{n}) \times i\) 即为所求。

    点击查看代码
    int main()
    {
        double m,n,ans=0;
        cin>>m>>n;
        for(int i=1;i<=m;i++)
        {
            ans+=1.0*i*(pow(1.0*i/m,n)-pow(1.0*(i-1)/m,n));
        }
        printf("%.8lf\n",ans);
        return 0;
    }
    

CF696B Puzzles

  • 目前在 \(fa\) 节点时,搜到子节点 \(x\) 和其他子节点的概率是相等的(因为不需要管具体是哪个节点),均为 \(\frac{1}{2}\)

  • \(f_{x}\) 表示 \(x\) 时间戳的期望值,状态转移方程为 \(f_{x}=1+f_{fa}+\frac{siz_{fa}-1-siz_{x}}{2}\) ,边界为 \(f_{1}=1\)

    点击查看代码
    struct node
    {
        int nxt,to;
    }e[100010];
    int head[100010],siz[100010],cnt=0;
    double f[100010];
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs(int x)
    {
        siz[x]=1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            dfs(e[i].to);
            siz[x]+=siz[e[i].to];
        }
    }
    void reroot(int x)
    {
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            f[e[i].to]=1+f[x]+(siz[x]-1-siz[e[i].to])/2.0;
            reroot(e[i].to);
        }
    }
    int main()
    {
        int n,u,v,i;
        cin>>n;
        for(i=2;i<=n;i++)
        {
            cin>>u;
            v=i;
            add(u,v);
        }
        dfs(1);
        f[1]=1;
        reroot(1);
        for(i=1;i<=n;i++)
        {
            printf("%.6lf ",f[i]);
        }
        return 0;
    }
    

luogu T459661 [CL-9G-ddd] 灯灯灯

  • 先考虑绿灯全部熄灭的情况,最后被熄灭的一定是绿灯,设还剩下 \(i(1 \le i \le n)\) 盏红灯,那么先前的 \(n-i+m-1\) 盏灯的开灯顺序是未知的,将红、绿灯视作 \(01\) 串,总方案数为 \(\dbinom{n-i+m-1}{n-i}\) ,概率为 \(\frac{\binom{n-i+m-1}{n-i}}{\binom{n+m}{n}}\) ,期望为 \(\frac{\binom{n-i+m-1}{n-i}}{\binom{n+m}{n}} \times i\)

  • 红灯同理,期望为 \(\frac{\binom{n-1+m-i}{m-i}}{\binom{n+m}{n}} \times i\)

  • 最终,有 \(\frac{\sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i}+\sum\limits_{i=1}^{m}i \times \binom{n-1+m-i}{m-i}}{\binom{n+m}{n}}=\frac{n}{m+1}+\frac{m}{n+1}\) 即为所求。

    • 证明
      • 先只看前半部分的 \(\sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i}\) ,有 \(\begin{aligned} \sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i} &=\sum\limits_{i=1}^{n}\binom{n-i+m-1}{n-i}+\sum\limits_{i=1}^{n}(i-1) \times \binom{n-i+m-1}{n-i} \\ &=\binom{n+m-1}{n-1}+\sum\limits_{i=1}^{n-1}i \times \binom{n-i+m-2}{n-i-1} \\ &=\dots \\ &=\sum\limits_{i=1}^{n}\binom{n+m-i}{n-i} \\ &=\binom{n+m}{n-1} \end{aligned}\) ,除以 \(\dbinom{n+m}{n}\) 后得 \(\dfrac{n}{m+1}\)
      • 同理,后半部分得到 \(\dfrac{m}{n+1}\)
    点击查看代码
    int main()
    {
        int n,m;
        cin>>n>>m;
        printf("%.6lf\n",1.0*n/(m+1)+1.0*m/(n+1));
        return 0;
    }
    

luogu P1365 WJMZBMR打osu! / Easy

  • 多倍经验: CF235B Let's Play Osu!

  • \(f_{i}\) 表示以 \(i\) 结尾的期望得分, \(len_{i}\) 表示以 \(i\) 结尾的极大的连续的 o 的期望长度,状态转移方程为 \(\begin{cases} len_{i}=len_{i-1}+1,f_{i}=f_{i-1}+(len_{i-1}+1)^{2}-len_{i-1}^{2}=f_{i-1}+2len_{i-1}+1 & s_{i}='o' \\ len_{i}=0,f_{i}=f_{i-1} & s_{i}='x' \\ len_{i}=\frac{len_{i-1}+1}{2},f_{i}=f_{i-1}+\frac{(len_{i-1}+1)^{2}-len_{i-1}^{2}}{2}=f_{i-1}+\frac{2len_{i-1}+1}{2} & s_{i}='?' \end{cases}\)

  • 最终,有 \(f_{n}\) 即为所求。

    点击查看代码
    double f[300010],len[300010];
    char s[300010];
    int main()
    {
        int n,i;
        cin>>n>>(s+1);
        for(i=1;i<=n;i++)
        {
            if(s[i]=='o')
            {
                len[i]=len[i-1]+1;
                f[i]=f[i-1]+2*len[i-1]+1;
            }
            if(s[i]=='x')
            {
                len[i]=0;
                f[i]=f[i-1];
            }
            if(s[i]=='?')
            {
                len[i]=(len[i-1]+1)/2.0;
                f[i]=f[i-1]+(2*len[i-1]+1)/2.0;
            }
        }
        printf("%.4lf\n",f[n]);
        return 0;
    }
    

牛客 NC274855 三角形

  • 桶统计即可。

    点击查看代码
    int a[110],vis[110];
    int main()
    {
        int n,sum=0,i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
            vis[a[i]]++;
            sum+=(vis[a[i]]>=3);
        }
        if(sum>=1)
        {
            cout<<"YES"<<endl;
        }
        else
        {
            cout<<"NO"<<endl;
        }
        return 0;
    }
    

牛客 NC274857 好数组

  • 解下绝对值不等式,发现在 \(a_{i}=0(a_{i} \le a_{j})\) 时原式不成立。

    点击查看代码
    int main()
    {
        int n,x,flag=0,i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>x;
            flag|=(x==0);
        }
        if(flag==0)
        {
            cout<<"YES"<<endl;
        }
        else
        {
            cout<<"NO"<<endl;
        }
        return 0;
    }
    

牛客 NC274862 前缀平方和序列

  • 序列内部的数都是正整数这个条件很好,说明前缀和是递增的(即已有顺序)。 \(1 \sim x\) 中的完全平方数共有 \(\left\lfloor \sqrt{x} \right\rfloor\) 个,从中选出 \(n\) 个,总方案数为 \(\frac{A_{\left\lfloor \sqrt{x} \right\rfloor}^{n}}{A_{n}^{n}}=\dbinom{\left\lfloor \sqrt{x} \right\rfloor}{n}\)
    • 如果没有序列内部的数都是正整数这个条件,则等价于求多重集的排列。

      点击查看代码
      const ll p=1000000007;
      ll qpow(ll a,ll b,ll p)
      {
          ll ans=1;
          while(b>0)
          {
              if(b&1)
              {
                  ans=ans*a%p;
              }
              b>>=1;
              a=a*a%p;
          }
          return ans;
      }
      ll C(ll n,ll m,ll p)
      {
          if(n>=m&&n>=0&&m>=0)
          {
              ll a=1,b=1;
              for(ll i=n-m+1;i<=n;i++)
              {
                  a=a*i%p;
              }
              for(ll i=1;i<=m;i++)
              {
                  b=b*i%p;
              }
              return a*qpow(b,p-2,p)%p;
          }
          else
          {
              return 0;
          }
      }
      int main()
      {
          ll n,x;
          cin>>n>>x;
          cout<<C(sqrt(x),n,p)<<endl;
          return 0;
      }
      

牛客 NC274864 走一个大整数迷宫

  • \(p^{k} \equiv 1 \bmod{(p-1)}\) ,得出 \(c_{i,j}=a_{i,j} \times p^{2^{b_{i,j}}} \equiv a_{i,j} \bmod{(p-1)}\)

  • \(BFS\) 过程中额外记录一个状态表示计数器 \(\mod{(p-1)}\) 的余数,时空复杂度为 \(O(nmp)\)

    点击查看代码
    int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}},vis[15][15][10010],a[15][15];
    struct node
    {
        int x,y,s,sum;
    };
    int bfs(int x,int y,int n,int m,int p)
    {
        int nx,ny,ns;
        queue<node>q;
        q.push(node{x,y,a[x][y]%p,0});
        vis[x][y][a[x][y]%p]=1;
        while(q.empty()==0)
        {
            node z=q.front();
            q.pop();
            if(z.x==n&&z.y==m&&z.s==0)
            {
                return z.sum;
            }
            for(int i=0;i<=3;i++)
            {
                nx=z.x+dir[i][0];
                ny=z.y+dir[i][1];
                ns=(z.s+a[nx][ny])%p;
                if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&vis[nx][ny][ns]==0)
                {
                    vis[nx][ny][ns]=1;
                    q.push(node{nx,ny,ns,z.sum+1});
                }
            }
        }
        return -1;
    }
    int main()
    {
        int n,m,p,i,j;
        cin>>n>>m>>p;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                cin>>a[i][j];
            }
        }
        cout<<bfs(1,1,n,m,p-1)<<endl;
        return 0;
    }
    

6.29

闲话

  • 早上跑操顺序在 \(23405\) 班后面,来的是数奥教练和另一个不认识的老师,数奥教练还远远得问 \(miaomiao\) 去哪里了。
  • 上午 @STA_Morlin 因在机房睡觉被 \(feifei\) \(D\) 了。
  • 偶然看见机房外面的垃圾桶里有一个TH的纸袋。
  • 下午来机房后碰见原班主任了;回机房后 \(huge\) 给放了每日一歌(事前没有通知),时间和初三的时候一样,用的是电脑音箱;没体活。
  • 晚上 @STA_Morlin 因在机房睡觉被 \(huge\) \(D\) 了。
  • 晚休的时候泡了桶泡面,没有人来查宿。

做题纪要

luogu P1654 OSU!

  • 由于 \(E(x^{2}) \ne E^{2}(x)\) ,故需要额外维护 \(E(x^{2})\) 的贡献。

  • \((x+1)^{3}-x^{3}=3x^{2}+3x+1\)

  • 状态转移方程为 \(\begin{cases} x_{i}=(x_{i-1}+1) \times p_{i} \\ x'^{2}_{i}=(x'^{2}_{i-1}+2x_{i-1}+1) \times p_{i} \\ f_{i}=f_{i-1}+(3x'^{2}_{i-1}+3x_{i-1}+1) \times p_{i} \end{cases}\)

    点击查看代码
    double f[100010],len1[100010],len2[100010];
    int main()
    {
        int n,i;
        double p;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>p;
            len1[i]=(len1[i-1]+1)*p;
            len2[i]=(len2[i-1]+2*len1[i-1]+1)*p;
            f[i]=f[i-1]+(3*len2[i-1]+3*len1[i-1]+1)*p;
        }
        printf("%.1lf\n",f[n]);
        return 0;
    }
    

luogu P1297 [国家集训队] 单选错位

  • 破环为链,令 \(a_{n+1}=a_{1}\)

  • 大力分讨。

    • \(a_{i}=a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i}}\)
    • \(a_{i}<a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i}} \times \frac{a_{i}}{a_{i+1}}=\frac{1}{a_{i+1}}\)
    • \(a_{i}>a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i+1}} \times \frac{a_{i+1}}{a_{i}}=\frac{1}{a_{i}}\)
  • 归纳下,有 \(\sum\limits_{i=1}^{n}\dfrac{1}{\max(a_{i},a_{i+1})}\)

    点击查看代码
    ll a[10000010];
    int main()
    {
        ll n,A,B,C,i;
        double ans=0;
        cin>>n>>A>>B>>C>>a[1];
        for(i=2;i<=n;i++)
        {
            a[i]=(a[i-1]*A%100000001+B)%100000001;
        }
        for(i=1;i<=n;i++)
        {
            a[i]=a[i]%C+1;
        }
        a[n+1]=a[1];
        for(i=1;i<=n;i++)
        {
            ans+=1.0/max(a[i],a[i+1]);
        }
        printf("%.3lf\n",ans);
        return 0;
    }
    

luogu P8804 [蓝桥杯 2022 国 B] 故障

  • 套个贝叶斯公式即可。

  • \(P(A_{i}|B)=\dfrac{P(A_{i})P(B|A_{i})}{P(B)}=\dfrac{P(A_{i})P(B|A_{i})}{\sum\limits_{k=1}^{n}P(A_{k})P(B|A_{k})}\)

    点击查看代码
    int a[45],p[45][45],vis[45],f[45];
    pair<double,int>ans[45];
    bool cmp(pair<double,int> a,pair<double,int> b)
    {
        return ((a.first==b.first)?(a.second<b.second):a.first>b.first);
    }
    int main()
    {
        int n,m,q,x,i,j,k;
        double sum=0;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                cin>>p[i][j];
            }
        }
        cin>>q;
        for(i=1;i<=q;i++)
        {
            cin>>x;
            vis[x]=1;
        }
        for(i=1;i<=n;i++)
        {
            ans[i].first=a[i]/100.0;
            ans[i].second=i;
            for(j=1;j<=m;j++)
            {
                ans[i].first*=(vis[j]==1)?p[i][j]/100.0:(100-p[i][j])/100.0;
            }
            sum+=ans[i].first;
        }
        sort(ans+1,ans+1+n,cmp);
        for(i=1;i<=n;i++)
        {
            printf("%d %.2lf\n",ans[i].second,ans[i].first/sum*100);
        }
        return 0;
    }
    

BZOJ1419 Red is good

  • 类似 luogu P2719 搞笑世界杯 ,设 \(f_{i,j}\) 表示还剩 \(i\) 张红牌, \(j\) 张黑牌的期望得到钱数,状态转移方程为 \(\begin{cases} f_{i,j}=i & j=0 \\ f_{i,j}=\max(0,\frac{i}{i+j} \times (f_{i-1,j}+1)+\frac{j}{i+j} \times (f_{i,j-1}-1)) & j \ne 0 \end{cases}\)

  • 最终,有 \(f_{r,b}\) 即为所求。

    点击查看代码
    double f[2][5010];
    int main()
    {
        int r,b,i,j;
        cin>>r>>b;
        for(i=1;i<=r;i++)
        {
            f[i&1][0]=i;
            for(j=1;j<=b;j++)
            {
                f[i&1][j]=max(0.0,1.0*i/(i+j)*(f[(i-1)&1][j]+1)+1.0*j/(i+j)*(f[i&1][j-1]-1));
            }
        }
        printf("%.6lf\n",floor(f[r&1][b]*1000000)/1000000);
        return 0;
    }
    

luogu P4206 [NOI2005] 聪聪与可可

  • 题目问的应该是期望多少时间,而不是多少步。

  • \(f_{i,j}\) 表示聪聪在 \(i\) 点,可可在 \(j\) 点时的期望步数;设 \(nxt_{i,j}\) 表示聪聪在 \(i\) 点,可可在 \(j\) 点时的聪聪下一段时间去的地方。状态转移方程为 \(f_{i,j}=\frac{f_{nxt_{nxt_{i,j}},j}+1+\sum\limits_{(j,k) \in E}(f_{nxt_{nxt_{i,j}},k}+1)}{du_{j}+1}\)

  • \(nxt_{i,j}\) 可以通过求出最短路预处理出,接着记忆化搜索即可。

    点击查看代码
    struct node
    {
        int nxt,to;
    }e[2010];
    int head[2010],dis[2010][2010],du[2010],nxt[2010][2010],cnt=0;
    double f[2010][2010];
    bool vis[2010][2010];
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    double dfs(int x,int y)
    {
        if(vis[x][y]==false)
        {
            vis[x][y]=true;
            if(x==y)//因为同一个点的nxt是INF(仅限于我代码),所以不能用nxt判
            {
                f[x][y]=0;
            }
            else
            {
                if(nxt[x][y]==y)
                {
                    f[x][y]=1;
                }	
                else
                {
                    f[x][y]=(dfs(nxt[nxt[x][y]][y],y)+1.0)/(1.0*du[y]+1.0);
                    for(int i=head[y];i!=0;i=e[i].nxt)
                    {
                        f[x][y]+=(dfs(nxt[nxt[x][y]][y],e[i].to)+1.0)/(1.0*du[y]+1.0);
                    }
                }
            }
        }
        return f[x][y];
    }
    int main()
    {
        int n,m,st,ed,u,v,i,j,k;
        cin>>n>>m>>st>>ed;
        memset(dis,0x3f,sizeof(dis));
        memset(nxt,0x3f,sizeof(nxt));
        for(i=1;i<=m;i++)
        {
            cin>>u>>v;
            add(u,v);
            add(v,u);
            dis[u][v]=dis[v][u]=1;
            du[u]++;
            du[v]++;
        }
        for(k=1;k<=n;k++)
        {
            for(i=1;i<=n;i++)
            {
                if(i!=k&&dis[i][k]!=0x3f3f3f3f)
                {
                    for(j=1;j<=n;j++)
                    {
                        if(j!=k&&i!=j&&dis[k][j]!=0x3f3f3f3f)
                        {
                            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
                        }
                    }
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(dis[i][j]<=2)
                {
                    nxt[i][j]=j;
                }
                else
                {
                    for(k=head[i];k!=0;k=e[k].nxt)
                    {
                        if(dis[e[k].to][j]==dis[i][j]-1)
                        {
                            nxt[i][j]=min(nxt[i][j],e[k].to);
                        }
                    }
                }
                
            }
        }
        printf("%.3lf\n",dfs(st,ed));
        return 0;
    }
    

CF148D Bag of mice

  • \(f_{i,j}\) 表示轮到公主抓时,袋子里还有 \(i\) 只白鼠, \(j\) 只黑鼠的概率。

  • 大力分讨,画搜索树。

    • 公主白鼠,概率为 \(\frac{i}{i+j}\)
    • 公主黑鼠,龙白鼠,概率为 \(\frac{j}{i+j} \times \frac{i}{i+j-1}\)
    • 公主黑鼠,龙黑鼠,跑出黑鼠,概率为 \(\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{j-2}{i+j-2}\)
    • 公主黑鼠,龙黑鼠,跑出白鼠,概率为 \(\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{i}{i+j-2}\)
  • 状态转移方程为 \(f_{i,j}=\frac{i}{i+j}+\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{j-2}{i+j-2} \times f_{i,j-3}+\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{i}{i+j-2} \times f_{i-1,j-2}\) ,边界为 \(\begin{cases} f_{i,0}=1 & i \in [1,w] \\ f_{0,j}=0 & j \in [1,b] \end{cases}\)

  • 最终,有 \(f_{w,b}\) 即为所求。

    点击查看代码
    double f[1010][1010];
    int main()
    {
        int w,b,i,j;
        cin>>w>>b;
        for(i=1;i<=w;i++)
        {
            f[i][0]=1;
            for(j=1;j<=b;j++)
            {
                f[i][j]=1.0*i/(i+j);
                if(j-3>=0)
                {
                    f[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*f[i][j-3];
                }
                if(i-1>=0&&j>=2)
                {
                    f[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*f[i-1][j-2];
                }
            }
        }
        printf("%.10lf\n",f[w][b]);
        return 0;
    }
    

CF768D Jon and Orbs

  • \(f_{i,j}\) 表示前 \(i\) 天取出了 \(j\) 种物品的概率,状态转移方程为 \(f_{i,j}=\frac{j}{n} \times f_{i-1,j}+\frac{n-j+1}{n} \times f_{i-1,j-1}\) ,边界为 \(f_{0,0}=1\)

  • 预处理到 \(10000\) 就差不多了,详细需要调和级数,但我不会。

    点击查看代码
    double f[10010][1010];
    int main()
    {
        int k,q,p,i,j;
        cin>>k>>q;
        f[0][0]=1;
        for(i=1;i<=10000;i++)
        {
            for(j=1;j<=k;j++)
            {
                f[i][j]=1.0*j/k*f[i-1][j]+1.0*(k-j+1)/k*f[i-1][j-1];
            }
        }
        for(i=1;i<=q;i++)
        {
            cin>>p;
            for(j=1;j<=10000;j++)
            {
                if(f[j][k]>=p/2000.0)
                {
                    cout<<j<<endl;
                    break;
                }
            }
        }
        return 0;
    }
    

luogu P10672 【MX-S1-T1】壁垒

luogu P10673 【MX-S1-T2】催化剂

luogu P10668 BZOJ2720 [Violet 5] 列队春游

  • 对题意的感性理解详见 BZOJ2720 列队春游

  • 枚举第 \(i\) 个人,站在第 \(j\) 个位置,视野为 \(k(1 \le k \le j-1)\) 的概率为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l} \ge h_{i}]}{n-k}\) ,期望为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l} \ge h_{i}]}{n-k} \times k\) ;视野为 \(k=j\) 时的概率为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}}\) ,期望为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times k\)

    • 可以通过 \(\dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k}}{A_{n-1}^{k}}=\dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]-k+1}{n-k}\) 来递推求解。
    点击查看代码
    int h[310],high[310],slow[310];
    int main()
    {
        int n,i,j,k;
        double ans=0,A;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>h[i];
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i!=j)
                {
                    if(h[i]>h[j])
                    {
                        slow[i]++;
                    }
                    else
                    {
                        high[i]++;
                    }
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                A=1;
                for(k=1;k<=min(j-1,slow[i]+1);k++)
                {
                    ans+=1.0/n*A*high[i]/(n-k)*k;
                    A*=1.0*(slow[i]-k+1)/(n-k);
                }
                ans+=1.0/n*A*k;
            }
        }
        printf("%.2lf\n",ans);
        return 0;
    }
    

luogu P2982 [USACO10FEB] Slowing down G

  • 单点修改。路径查询板子。

    点击查看代码
    struct node
    {
        int nxt,to;
    }e[200010];
    int head[200010],c[200010],cc[200010],siz[200010],fa[200010],dep[200010],son[200010],top[200010],dfn[200010],cnt=0,tot=0;
    struct SMT
    {
        struct SegmentTree
        {
            int l,r,sum;
        }tree[800010];
        int lson(int x)
        {
            return x*2;
        }
        int rson(int x)
        {
            return x*2+1;
        }
        void pushup(int rt)
        {
            tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
        }
        void build(int rt,int l,int r)
        {
            tree[rt].l=l;
            tree[rt].r=r;
            if(l==r)
            {
                tree[rt].sum=cc[l];
                return;
            }
            int mid=(l+r)/2;
            build(lson(rt),l,mid);
            build(rson(rt),mid+1,r);
            pushup(rt);
        }
        void update(int rt,int pos,int val)
        {
            if(tree[rt].l==tree[rt].r)
            {
                tree[rt].sum+=val;
                return;
            }
            int mid=(tree[rt].l+tree[rt].r)/2;
            if(pos<=mid)
            {
                update(lson(rt),pos,val);
            }
            else
            {
                update(rson(rt),pos,val);
            }
            pushup(rt);
        }
        int query(int rt,int x,int y)
        {
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                return tree[rt].sum;
            }
            int mid=(tree[rt].l+tree[rt].r)/2,ans=0;
            if(x<=mid)
            {
                ans+=query(lson(rt),x,y);
            }
            if(y>mid)
            {
                ans+=query(rson(rt),x,y);
            }
            return ans;
        }
    }T;
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs1(int x,int father)
    {
        siz[x]=1;
        fa[x]=father;
        dep[x]=dep[father]+1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=father)
            {
                dfs1(e[i].to,x);
                siz[x]+=siz[e[i].to];
                son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x];
            }
        }
    }
    void dfs2(int x,int father,int id)
    {
        top[x]=id;
        tot++;
        dfn[x]=tot;
        cc[tot]=c[x];
        if(son[x]!=0)
        {
            dfs2(son[x],x,id);
            for(int i=head[x];i!=0;i=e[i].nxt)
            {
                if(e[i].to!=father&&e[i].to!=son[x])
                {
                    dfs2(e[i].to,x,e[i].to);
                }
            }
        }
    }
    void update1(int pos,int val)
    {
        T.update(1,dfn[pos],val);
    }
    int query1(int u,int v)
    {
        int ans=0;
        while(top[u]!=top[v])
        {
            if(dep[top[u]]>dep[top[v]])
            {
                ans+=T.query(1,dfn[top[u]],dfn[u]);
                u=fa[top[u]];
            }
            else
            {
                ans+=T.query(1,dfn[top[v]],dfn[v]);
                v=fa[top[v]];
            }
        }
        if(dep[u]<dep[v])
        {
            ans+=T.query(1,dfn[u],dfn[v]);
        }
        else
        {
            ans+=T.query(1,dfn[v],dfn[u]);
        }
        return ans;
    }
    int main()
    {
        int n,u,v,i;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        dfs1(1,0);
        dfs2(1,0,1);
        T.build(1,1,n);
        for(i=1;i<=n;i++)
        {
            cin>>u;
            cout<<query1(1,u)<<endl;
            update1(u,1);
        }
        return 0;
    }
    

BZOJ2969 矩形粉刷

  • 正难则反,考虑求不被小 M 粉刷过的格子个数的概率。

  • \(f_{i,j}\) 表示 \((i,j)\) 不被刷到 \(1\) 个随机矩形刷到的概率,状态转移方程为 \(f_{i,j}=(\frac{i-1}{w})^{2}+(\frac{w-i}{w})^{2}+(\frac{j-1}{h})^{2}+(\frac{h-j}{h})^{2}-(\frac{i-1}{w} \times \frac{j-1}{h})^{2}-(\frac{i-1}{w} \times \frac{h-j}{h})^{2}-(\frac{w-i}{w} \times \frac{j-1}{h})^{2}-(\frac{w-i}{w} \times \frac{h-j}{h})^{2}\)

    • 建议画图,容斥一下,答案部分等于上面加下面加左面加右面减左上减右上减左下减右下。
  • 最终,有 \(\sum\limits_{i=1}^{w}\sum\limits_{j=1}^{h}(1-f_{i,j}^{k})\) 即为所求。

    点击查看代码
    int main()
    {
        int k,w,h,i,j;
        double ans=0;
        cin>>k>>w>>h;
        for(i=1;i<=w;i++)
        {
            for(j=1;j<=h;j++)
            {
                ans+=1-pow(pow(1.0*(i-1)/w,2)+pow(1.0*(w-i)/w,2)+pow(1.0*(j-1)/h,2)+pow(1.0*(h-j)/h,2)-pow(1.0*(i-1)/w*1.0*(j-1)/h,2)-pow(1.0*(i-1)/w*1.0*(h-j)/h,2)-pow(1.0*(w-i)/w*1.0*(j-1)/h,2)-pow(1.0*(w-i)/w*1.0*(h-j)/h,2),k);
            }
        }
        printf("%.0lf\n",ans);
        return 0;
    }
    

SP1026 FAVDICE - Favorite Dice

  • \(f_{i}\) 表示当前已经掷了 \(i\) 种面,要掷完 \(n\) 种面的期望次数,有 \(\begin{cases} f_{i}=0 & i=n \\ f_{i}= \frac{i}{n} \times (f_{i}+1)+ \frac{n-i}{n} \times (f_{i+1}+1) & i \ne n \end{cases}\) ,移项得 \(\begin{cases} f_{i}=0 & i=n \\ f_{i}=f_{i+1}+ \frac{n}{n-i} & i \ne n \end{cases}\)

    点击查看代码
    double f[1010];
    int main()
    {
        int t,n,i,j;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n;
            f[n]=0;
            for(j=n-1;j>=0;j--)
            {
                f[j]=f[j+1]+1.0*n/(n-j);
            }
            printf("%.2lf\n",f[0]);
        }
        return 0;
    }
    

luogu P2059 [JLOI2013] 卡牌游戏

  • 感觉有点像 约瑟夫问题 ,考虑逆推。

  • 由于牌是放回的,故剩下 \(i\) 个人的状态能继承剩下 \(i-1\) 个人的状态。

  • \(f_{i,j}\) 表示剩下 \(i\) 个人时,从庄主开始顺时针数第 \(j\) 个人胜出的概率,状态转移方程为 \(f_{i,j}=\sum\limits_{k=1}^{m}\frac{[(a_{k}-1) \bmod i+1 >j] \times f_{i-1,j+i-((a_{k}-1) \bmod i+1)}+[(a_{k}-1) \bmod i+1 <j] \times f_{i-1,j-((a_{k}-1) \bmod i+1)}}{m}\) ,边界为 \(f_{1,1}=1\)

    点击查看代码
    int a[110];
    double f[110][110];
    int main()
    {
        int n,m,i,j,k;
        cin>>n>>m;
        for(i=1;i<=m;i++)	
        {
            cin>>a[i];
        }
        f[1][1]=1;
        for(i=2;i<=n;i++)
        {
            for(j=1;j<=i;j++)
            {
                for(k=1;k<=m;k++)
                {
                    if((a[k]-1)%i+1>j)
                    {
                        f[i][j]+=f[i-1][i+j-((a[k]-1)%i+1)]/(1.0*m);
                    }
                    if((a[k]-1)%i+1<j)
                    {
                        f[i][j]+=f[i-1][j-((a[k]-1)%i+1)]/(1.0*m);
                    }
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            printf("%.2lf",f[n][i]*100);
            cout<<"% ";
        }
        return 0;
    }
    

[ARC180A] ABA and BAB

  • 两种操作等价于在一定条件下删除 ABBA

  • 所有极长的 ABBA 的长度除以 \(2\) 向上取整后的结果即为所求。

    点击查看代码
    const ll p=1000000007;
    char s[250010];
    int main()
    {
        ll n,ans=1,len=0,i;
        scanf("%lld%s",&n,s+1);
        for(i=1;i<=n;i++)
        {
            if(s[i]!=s[i-1])
            {
                len++;
            }
            else
            {
                ans=ans*((ll)ceil(1.0*len/2)%p)%p;
                len=1;
            }
        }
        ans=ans*((ll)ceil(1.0*len/2)%p)%p;
        cout<<ans<<endl;
        return 0;
    }
    

UVA11181 条件概率 Probability|Given

  • 状压枚举计算即可。

    点击查看代码
    double p[50],f[50];
    int main()
    {
        int n,r,cnt=0,i,j;
        double sum,num;
        while(cin>>n>>r)
        {
            if(n==0&&r==0)
            {
                break;
            }
            else
            {
                cnt++;
                sum=0;
                memset(f,0,sizeof(f));
                for(i=1;i<=n;i++)
                {
                    cin>>p[i];
                }
                for(i=0;i<=(1<<n)-1;i++)			
                {
                    if(__builtin_popcount(i)==r)
                    {
                        num=1;
                        for(j=0;j<=n-1;j++)
                        {
                            num*=((i>>j)&1)?p[j+1]:1-p[j+1];
                        }
                        for(j=0;j<=n-1;j++)
                        {
                            f[j+1]+=((i>>j)&1)*num;
                        }
                        sum+=num;
                    }
                }
                cout<<"Case "<<cnt<<":"<<endl;
                for(i=1;i<=n;i++)
                { 
                    printf("%.6lf\n",f[i]/sum);
                }
            }
        }
        return 0;
    }
    

6.30

闲话

  • 早上有体活,在宿舍颓。
  • 上午 \(feifei\) 不顾我们概率期望还没写完的事实,非让我们开数位 \(DP\) ,称按照 POJ3208 Apocalypse Somedayluogu P4127 [AHOI2009] 同类分布 的做题情况来决定看不看视频。
  • 高一的放假了,收拾行李,让明天自己去 HZ 。
  • 下午 \(feifei\) 让我们先把概率期望没写的题跳了来写数位 \(DP\) ,还 \(D\) 了我们。
  • 晚上 \(feifei\) 收手机的手法和寒假集训 \(miaomiao\) 手法一样,“还有没有要交的?再给你们一次机会”; \(feifei\)@wang54321 认成了 @Pursuing_OIer \(feifei\) 说了下明天搬到 HZ 的“具体事项”——“明天早上不跑操,起床后直接把行李拉到机房楼下”。

做题纪要

CF280C Game on Tree

  • 一个点被删掉当且仅当删掉了这个点或这个点的祖先节点之一,而其他节点并不影响删除。有点 \(x\) 被删掉的期望次数为 \(\dfrac{1}{dep_{x}}\)

  • 最终,有 \(\sum\limits_{i=1}^{n}\dfrac{1}{dep_{i}}\) 即为所求。

    点击查看代码
    struct node
    {
        int nxt,to;
    }e[200010];
    int head[200010],dep[200010],cnt=0;
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs(int x,int fa)
    {
        dep[x]=dep[fa]+1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa)
            {
                dfs(e[i].to,x);
            }
        }
    }
    int main()
    {
        int n,u,v,i;
        double ans=0;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        dfs(1,0);
        for(i=1;i<=n;i++)
        {
            ans+=1.0/dep[i];
        }
        printf("%.8lf\n",ans);
        return 0;
    }	
    

luogu P2111 考场奇遇

  • \(f_{i,j}\) 表示做到第 \(i\) 道题时,对了 \(j\) 道题的概率。状态转移方程为 \(f_{i,j}= \begin{cases} f_{i-1,j-1} \times A \%+f_{i-1,j} \times (1-A \%) & s_{i}=1 \\ f_{i-1,j} \times A \%+f_{i-1,j-1} \times (1-A \%) & s_{i}=0 \end{cases}\)

  • 最终,有 \(\sum\limits_{i=q}^{n}f_{n,i}\) 即为所求。

    点击查看代码
    double f[2][10010];
    int main()
    {
        int n,q,i,j;
        double a,ans=0;
        char s;
        cin>>n>>a>>q;
        a/=100;
        f[0][0]=1;
        for(i=1;i<=n;i++)
        {
            cin>>s;
            if(s=='1')
            {
                f[i&1][0]=f[(i-1)&1][0]*(1.0-a);
            }
            else
            {
                f[i&1][0]=f[(i-1)&1][0]*a;
            }
            for(j=1;j<=i;j++)
            {
                if(s=='1')
                {
                    f[i&1][j]=f[(i-1)&1][j-1]*a+f[(i-1)&1][j]*(1.0-a);
                }
                else
                {
                    f[i&1][j]=f[(i-1)&1][j]*a+f[(i-1)&1][j-1]*(1.0-a);
                }
            }
        }
        for(i=q;i<=n;i++)
        {
            ans+=f[n&1][i];
        }
        printf("%.3lf\n",ans);
        return 0;
    }
    

luogu P1850 [NOIP2016 提高组] 换教室

  • 因变量重名,以下所称的 \(\{ p \}\) 指题面中的 \(\{ k \}\)

  • \(f_{i,j,0/1}\) 表示第 \(i\) 个时间段成功换了 \(j\) 个教室,当前不申请换/申请换教室的耗费的体力值的总和的最小期望,状态转移方程为 \(\begin{cases} f_{i,j,0}=\min \begin{cases} f_{i-1,j,0}+dis_{c_{i-1},c_{i}} \\ f_{i-1,j,1}+(1-p_{i-1}) \times dis_{c_{i-1},c_{i}}+p_{i-1} \times dis_{d_{i-1},c_{i}} \end{cases} \\ f_{i,j,1}=\min \begin{cases} f_{i-1,j-1,0}+(1-p_{i}) \times dis_{c_{i-1},c_{i}}+p_{i} \times dis_{c_{i-1},d_{i}} \\ f_{i-1,j-1,1}+(1-p_{i-1})(1-p_{i}) \times dis_{c_{i-1},c_{i}}+p_{i-1}p_{i} \times dis_{d_{i-1},d_{i}}+(1-p_{i-1})p_{i} \times dis_{c_{i-1},d_{i}}+p_{i-1}(1-p_{i}) \times dis_{d_{i-1},c_{i}} \end{cases} \end{cases}\) ,边界为 \(f_{1,0,0}=f_{1,1,1}=0\)

  • 最终,有 \(\min\limits_{i=0}^{m} \{ f_{n,i,1},f_{n,i,0} \}\) 即为所求。

    点击查看代码
    int dis[2010][2010],c[2010],d[2010];
    double p[2010],f[2010][2010][2];
    int main()
    {
        int n,m,v,e,x,y,z,i,j,k;
        double ans=0x3f3f3f3f;
        cin>>n>>m>>v>>e;
        memset(dis,0x3f,sizeof(dis));
        for(i=1;i<=n;i++)
        {
            cin>>c[i];
        }
        for(i=1;i<=n;i++)
        {
            cin>>d[i];
        }
        for(i=1;i<=n;i++)
        {
            cin>>p[i];
        }
        for(i=1;i<=v;i++)
        {
            dis[i][i]=0;
        }
        for(i=1;i<=e;i++)
        {
            cin>>x>>y>>z;
            dis[x][y]=min(dis[x][y],z);
            dis[y][x]=min(dis[y][x],z);
        }
        for(k=1;k<=v;k++)
        {
            for(i=1;i<=v;i++)
            {
                for(j=1;j<=v;j++)
                {
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            for(j=0;j<=m;j++)
            {
                f[i][j][0]=f[i][j][1]=0x3f3f3f3f;
            }
        }
        f[1][0][0]=f[1][1][1]=0;
        for(i=2;i<=n;i++)
        {
            for(j=0;j<=min(i,m);j++)
            {
                f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+(1-p[i-1])*dis[c[i-1]][c[i]]+p[i-1]*dis[d[i-1]][c[i]]);
                if(j-1>=0)
                {
                    f[i][j][1]=min(f[i-1][j-1][0]+(1-p[i])*dis[c[i-1]][c[i]]+p[i]*dis[c[i-1]][d[i]],f[i-1][j-1][1]+(1-p[i-1])*(1-p[i])*dis[c[i-1]][c[i]]+p[i-1]*p[i]*dis[d[i-1]][d[i]]+(1-p[i-1])*p[i]*dis[c[i-1]][d[i]]+p[i-1]*(1-p[i])*dis[d[i-1]][c[i]]);
                }
            }
        }
        for(i=0;i<=m;i++)
        {
            ans=min(ans,min(f[n][i][0],f[n][i][1]));
        }
        printf("%.2lf\n",ans);
        return 0;
    }
    

luogu P2473 [SCOI2008] 奖励关

  • \(f_{i,s}\) 表示 \(1 \sim i-1\) 次获取宝物的状态为 \(s\) 时, \(i \sim k\) 次的最大期望得分。状态转移方程为 \(f_{i,s}=\sum\limits_{j=1}^{n}\frac{[S_{j} \in s] \times \max(f_{i+1,s},f_{i+1,s|(1<<(j-1))}+p_{j})+[S_{j} \notin s] \times f_{i+1,s}}{n}\)

  • 最终,有 \(f_{1,0}\) 即为所求。

    点击查看代码
    int p[103],vis[103];
    double f[103][(1<<16)+10];
    int main()
    {
        int k,n,x,i,s,j;
        cin>>k>>n;
        for(i=1;i<=n;i++)
        {
            cin>>p[i];
            while(cin>>x)
            {
                if(x==0)
                {
                    break;
                }
                else
                {
                    vis[i]|=(1<<(x-1));
                }
            }
        }
        for(i=k;i>=1;i--)
        {
            for(s=0;s<=(1<<n)-1;s++)
            {
                for(j=1;j<=n;j++)
                {
                    f[i][s]+=1.0*(((s&vis[j])==vis[j])?max(f[i+1][s],f[i+1][s|(1<<(j-1))]+p[j]):f[i+1][s])/n;
                }
            }
        }
        printf("%.6lf\n",f[1][0]);
        return 0;
    }
    

luogu P4284 [SHOI2014] 概率充电器

  • \(P(A \bigcup B)=P(A)+P(B)-P(A \bigcap B)=P(A)+P(B)-P(A) \times P(B)\)

  • 在第一遍 \(DFS\) 中,设 \(f_{x}\) 表示 \(x\) 充电的概率,初始值为 \(q_{x} \%\) ,每增加一棵子树,均有 \(f_{x}=f_{x}+f_{y} \times p_{x,y}\%-f_{x} \times f_{y} \times p_{x,y}\%\)

  • 在第二遍 \(DFS\) 中,同理,设 \(f_{fa_{x}}=k+f_{x} \times p_{fa_{x},x}\%-k \times f_{x} \times p_{fa_{x},x}\%\) ,解得 \(k=\frac{f_{fa_{x}}-f_{x} \times p_{fa_{x},x}\%}{1-f_{x} \times p_{fa_{x},x}\%}\) ,此时有 \(f_{x}=f_{x}+k \times p_{fa_{x},x}\%-f_{x} \times k \times p_{fa_{x},x}\%\) ,特别地,当 \(1-f_{x} \times p_{fa_{x},x}\%=0\) 时规定 \(k=0\)

    • 类似换根过程中的删除影响。
  • 最终,有 \(\sum\limits_{i=1}^{n}f_{i}\) 即为所求。

    点击查看代码
    const double eps=1e-10;
    struct node
    {
        int nxt,to;
        double p;
    }e[1000010];
    int head[1000010],cnt=0;
    double q[1000010],f[1000010];
    void add(int u,int v,double p)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        e[cnt].p=p;
        head[u]=cnt;
    }
    void dfs(int x,int fa)
    {
        f[x]=q[x];
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa)
            {
                dfs(e[i].to,x);
                f[x]+=f[e[i].to]*e[i].p-f[x]*f[e[i].to]*e[i].p;
            }
        }
    }
    void reroot(int x,int fa)
    {
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa)
            {
                if(1-f[e[i].to]*e[i].p>eps)
                {
                    double k=(f[x]-f[e[i].to]*e[i].p)/(1-f[e[i].to]*e[i].p);
                    f[e[i].to]+=k*e[i].p-f[e[i].to]*k*e[i].p;
                }
                reroot(e[i].to,x);
            }
        }
    }
    int main()
    {
        int n,u,v,p,i;
        double ans=0;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>u>>v>>p;
            add(u,v,p/100.0);
            add(v,u,p/100.0);
        }
        for(i=1;i<=n;i++)
        {
            cin>>q[i];
            q[i]/=100.0;
        }
        dfs(1,0);
        reroot(1,0);
        for(i=1;i<=n;i++)
        {
            ans+=f[i];
        }
        printf("%.6lf\n",ans);
        return 0;
    }
    

luogu P3232 [HNOI2013] 游走

  • \(f_{i}\) 表示 \(i\) 号顶点的期望经过次数,状态转移方程为 \(f_{i}=[i=1 \lor i=n]+[i \ne n] \times [j \ne n] \times \sum\limits_{(i,j) \in E}\frac{f_{j}}{du_{j}}=[i=1 \lor i=n]+\sum\limits_{i=1}^{n}\frac{[i \ne n] \times [j \ne n] \times [(i,j) \in E] \times f_{j}}{du_{j}}\)

  • 类似 luogu P2973 [USACO10HOL] Driving Out the Piggies G ,移项得到方程组 \(\begin{cases} f_{1}-\sum\limits_{i=1}^{n}\frac{[j \ne n] \times [(1,j) \in E]}{du_{j}} \times f_{j}=1 \\ f_{i}-\sum\limits_{i=1}^{n}\frac{[j \ne n] \times [(i,j) \in E]}{du_{j}} \times f_{j}=0 & 1<i<n \\ f_{n}=1 \end{cases}\) ,高斯消元解一下。

  • \(g_{i}\) 表示第 \(i\) 条边的期望经过次数,状态转移方程为 \(g_{i}=[u_{i} \ne n] \times \frac{f_{u_{i}}}{du_{u_{i}}}+[v_{i} \ne n] \times \frac{f_{v_{i}}}{du_{v_{i}}}\)

  • 由排序不等式,期望经过次数越多的边标号越小。最终,将 \(g\) 升序排序后有 \(\sum\limits_{i=1}^{m}g_{i}(m-i+1)\) 即为所求。

    点击查看代码
    const double eps=1e-12;
    int du[510],dis[510][510],u[125010],v[125010];
    double a[510][510],f[510],g[125010];
    int main()
    {
        int n,m,val,i,j,k;
        double ans=0;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            cin>>u[i]>>v[i];
            dis[u[i]][v[i]]=dis[v[i]][u[i]]=1;
            du[u[i]]++;
            du[v[i]]++;
        }
        for(i=1;i<=n;i++)
        {
            a[i][i]=1;
            for(j=1;j<=n;j++)
            {
                if(j!=i)
                {
                    a[i][j]=-1.0*(i!=n)*(j!=n)*(dis[i][j]==1)/du[j];
                }
            }
            a[i][n+1]=(i==1||i==n);
        }
        for(i=1;i<=n;i++)
        {
            val=i;
            for(j=i;j<=n;j++)
            {
                if(fabs(a[j][i])-fabs(a[val][i])>eps)
                {
                    val=j;
                }
            }
            for(j=1;j<=n+1;j++)
            {
                swap(a[i][j],a[val][j]);
            }
            if(a[i][i]!=0)
            {
                for(j=1;j<=n;j++)
                {
                    if(j!=i)
                    {
                        for(k=i+1;k<=n+1;k++)
                        {
                            a[j][k]-=a[i][k]*a[j][i]/a[i][i];
                        }
                    }
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            f[i]=a[i][n+1]/a[i][i];
        }
        for(i=1;i<=m;i++)
        {
            g[i]=(u[i]!=n)*f[u[i]]/(1.0*du[u[i]])+(v[i]!=n)*f[v[i]]/(1.0*du[v[i]]);
        }
        sort(g+1,g+1+m);
        for(i=1;i<=m;i++)
        {
            ans+=g[i]*(m-i+1);
        }
        printf("%.3lf\n",ans);
        return 0;
    }
    

北京建筑大学2024年程序设计竞赛(同步赛) F 买蛋糕

  • 条件语句。

    点击查看代码
    int main()
    {
        int n,a,b,c,sum=0,i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a>>b>>c;
            sum+=(a+b+c>=100);
        }
        cout<<sum<<endl;
        return 0;
    }
    

北京建筑大学2024年程序设计竞赛(同步赛) G 区间翻转

  • 只关注元素 \(1\) 所处的位置即可。

    点击查看代码
    int main()
    {
        int n,k,m,l,r,i,j;
        cin>>n>>k>>m;
        for(i=1;i<=m;i++)
        {
            cin>>l>>r;
            if(l<=k&&k<=r)
            {
                k=r-(k-l);  
            }
        }
        cout<<k<<endl;
        return 0;
    }
    

北京建筑大学2024年程序设计竞赛(同步赛) I 洗牌

  • 模拟。

    点击查看代码
    int a[100],b[100];
    int main()
    {
        int n,l,r,i,j,k;
        cin>>n;
        for(i=1;i<=54;i++)
        {
            a[i]=i;
        }
        for(i=1;i<=n;i++)
        {
            cin>>l>>r;
            for(j=1;j<=r;j++)
            {
                b[j]=a[j];
            }
            for(j=1,k=l;k<=r;j++,k++)
            {
                a[j]=b[k];
            }
            for(j=r-l+2,k=1;k<=l-1;j++,k++)
            {
                a[j]=b[k];
            }
        }
        for(i=1;i<=54;i++)
        {
            cout<<a[i]<<" ";
        }
        return 0;
    }
    

北京建筑大学2024年程序设计竞赛(同步赛) A 寿命修改

  • 最多只会死亡 \(n\) 只青蛙,对于死亡的青蛙线段树上暴力找然后单点修改即可,否则同正常的线段树区间修改。

    点击查看代码
    ll a[200010];
    struct SMT
    {
        struct SegmentTree
        {
            ll l,r,sum,lazy,minn,len;
        }tree[800010];
        ll lson(ll x)
        {
            return x*2;
        }
        ll rson(ll x)
        {
            return x*2+1;
        }
        void pushup(ll rt)
        {
            tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
            tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn);
            tree[rt].len=tree[lson(rt)].len+tree[rson(rt)].len;
        }
        void build(ll rt,ll l,ll r)
        {
            tree[rt].l=l;
            tree[rt].r=r;
            tree[rt].lazy=0;
            if(l==r)
            {
                tree[rt].sum=tree[rt].minn=a[l];
                tree[rt].len=1;
                return;
            }
            ll mid=(l+r)/2;
            build(lson(rt),l,mid);
            build(rson(rt),mid+1,r);
            pushup(rt);
        }
        void pushdown(ll rt)
        {
            if(tree[rt].lazy!=0)
            {
                tree[lson(rt)].lazy+=tree[rt].lazy;
                tree[rson(rt)].lazy+=tree[rt].lazy;
                tree[lson(rt)].sum+=tree[rt].lazy*tree[lson(rt)].len;
                tree[rson(rt)].sum+=tree[rt].lazy*tree[rson(rt)].len;
                tree[lson(rt)].minn+=tree[rt].lazy;
                tree[rson(rt)].minn+=tree[rt].lazy;
                tree[rt].lazy=0;
            }
        }
        void update(ll rt,ll x,ll y,ll val)
        {
            if(tree[rt].len==0)
            {
                return;
            }
            if(tree[rt].l==tree[rt].r)
            {
                tree[rt].sum+=val;
                tree[rt].minn+=val;
                if(tree[rt].minn<=0)
                {
                    tree[rt].sum=tree[rt].lazy=0;
                    tree[rt].minn=0x3f3f3f3f;
                    tree[rt].len=0;
                }
                return;
            }
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                if(tree[rt].minn+val>0)
                {
                    tree[rt].lazy+=val;
                    tree[rt].sum+=val*tree[rt].len;
                    tree[rt].minn+=val;
                    return;
                }
            }
            pushdown(rt);
            ll mid=(tree[rt].l+tree[rt].r)/2;
            if(x<=mid)
            {
                update(lson(rt),x,y,val);
            }
            if(y>mid)
            {
                update(rson(rt),x,y,val);
            }
            pushup(rt);
        }
        ll query(ll rt,ll x,ll y)
        {
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                return tree[rt].sum;
            }
            pushdown(rt);
            ll mid=(tree[rt].l+tree[rt].r)/2,ans=0;
            if(x<=mid)
            {
                ans+=query(lson(rt),x,y);
            }
            if(y>mid)
            {
                ans+=query(rson(rt),x,y);
            }
            return ans;
        }
    }T;
    int main()
    {
        ll n,m,pd,l,r,x,i;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        T.build(1,1,n);
        for(i=1;i<=m;i++)
        {
            cin>>pd>>l>>r;
            if(pd==1)
            {
                cin>>x;
                T.update(1,l,r,x);
            }
            else
            {
                cout<<T.query(1,l,r)<<endl;
            }
        }
        return 0;
    }
    

牛客 NC275421 嘤嘤不想做计几喵

牛客 NC275501 嘤嘤不想打怪兽喵

牛客 NC275503 嘤嘤不想买东西喵

牛客 NC275631 嘤嘤不想求异或喵

牛客 NC275518 嘤嘤不想解方程喵

[ABC360A] A Healthy Breakfast

  • 模拟。

    点击查看代码
    int vis[200];
    char s[4];
    int main()
    {
        for(int i=1;i<=3;i++)
        {
            cin>>s[i];
            vis[s[i]]=i;
        }
        if(vis['R']<vis['M'])
        {
            cout<<"Yes"<<endl;
        }
        else
        {
            cout<<"No"<<endl;
        }
        return 0;
    }
    
posted @ 2024-06-27 19:54  hzoi_Shadow  阅读(80)  评论(4编辑  收藏  举报
扩大
缩小