zoukankan      html  css  js  c++  java
  • 20181101

    T1 4019: 白玉楼前(youmu)

    题目描述

    妖梦现在要玩幽幽子的游戏,她才能拿回自己的半灵。
    游戏规则是这样的:
    幽幽子有 n 个点,现在她让妖梦对每个点随机一条出边(随机到每个点的概率都相等),然后得到一张图。(注意:可以自环)
    如果这张图任意一个点沿着边走两步(显然这样的走法唯一)都能到达自身,则幽幽子可以通关。
    现在幽幽子想问妖梦,她通关的概率是多少?
    两个图不同,当且仅当存在一条边出现在图 A 中且不出现在图 B 中。图中的点有编号,边无编号。答案 mod 998244353。

    题解

    神犇都想到题解了(所以我没想到)
    考虑dp,设fif_i表示前i个点已经匹配完的方案数
    fi=fi1+(i1)fi2f_i=f_{i-1}+(i-1)f_{i-2}
    预处理f数组即可,最后乘(1/n)n(1/n)^n
    具体见代码

    #include <bits/stdc++.h>
    #define E register
    using namespace std;
    const int P=998244353,N=5e5+5;
    int T,n,jc[N],ny[N],f[N],ans[N];
    inline int K(E int x,E int y){
        int A=1;while(y){
            if (y&1) A=1ll*A*x%P;
            x=1ll*x*x%P;y>>=1;
        }
        return A;
    }
    int main(){
        f[0]=f[1]=1;
        for (int i=2;i<N;i++)
            f[i]=(f[i-1]+1ll*(i-1)*f[i-2]%P)%P;
        for (scanf("%d",&T);T--;)
            scanf("%d",&n),
            printf("%d
    ",1ll*K(K(n,P-2),n)*f[n]%P);
        return 0;
    }
    

    T2 4020: 式神守护(yukari)

    题目描述

    紫妈有n 个隙间排成一列,每个隙间都有一个权值val 。
    她可以选出某些隙间来召唤式神:一组隙间能成功召唤式神当且仅当他们的权值和为m的倍数。(可以是0 倍)
    现在紫妈试图召唤 Q次式神,每次给出一个l和r ,她试图在第l到r个隙间中召唤式神,她会选择其中一些隙间(不一定需要连续的一些)召唤式神。她想知道,有多少种方案可以成功召唤式神。

    题解

    考场只想到了线段树,然鹅效率不优秀(只有O(nlognm2)O(nlogn·m^2))
    考虑分治
    设要处理[l,r][l,r]这一段区间内的答案
    我们可以把询问没有跨过mid的递归下去求解,则留在这段区间的询问,左端点在[l,mid][l,mid]内,右端点在[mid+1,r][mid+1,r]
    考虑dpdp
    f[i][j]f[i][j]表示从midmid向左到ii,余数为jj的方案数
    g[i][j]g[i][j]表示从mid+1mid+1向右到ii,余数为jj的方案数
    可以很快得到dp式子:
    f[i][j]=f[i+1][j]+f[i+1][(ja[i]+m)f[i][j]=f[i+1][j]+f[i+1][(j-a[i]+m)%m]]
    g[i][j]=g[i1][j]+g[i1][(ja[i]+m)g[i][j]=g[i-1][j]+g[i-1][(j-a[i]+m)%m]]
    所以对于一个跨过midmid的询问[L,R][L,R],我们可以得到他的答案
    ans=j=0m1f[L][j]g[R][(mj)ans=sum_{j=0}^{m-1}f[L][j]*g[R][(m-j)%m]]
    效率O(nlognm)O(nlogn·m)
    具体见代码

    #include <bits/stdc++.h>
    #define I inline
    #define _(d) while(d(isdigit(c=getchar())))
    using namespace std;
    I int R(){
        int x;char c;_(!);x=(c^48);
        _()x=(x<<3)+(x<<1)+(c^48);return x;
    }
    const int N=2e5+5,P=1e9+7;
    int n,m,a[N],q,s[N],f[N][20],g[N][20];
    struct O{int l,r,d;}p[N],h[N];
    void solve(int l,int r,int ql,int qr){
        if (l==r){
            for (int i=ql;i<=qr;i++)
                s[p[i].d]=(a[l]<1)+1;
            return;
        }
        int mid=l+r>>1,cl=ql,cr=qr,kl;
        for (int i=ql;i<=qr;i++){
            if (p[i].r<=mid) h[cl++]=p[i];
            if (p[i].l>mid) h[cr--]=p[i];
        }
        kl=cl;
        for (int i=ql;i<=qr;i++)
            if (p[i].l<=mid && p[i].r>mid) h[kl++]=p[i];
        for (int i=ql;i<=qr;i++) p[i]=h[i];
        if (cl>ql) solve(l,mid,ql,cl-1);
        if (cr<qr) solve(mid+1,r,cr+1,qr);
        f[mid][0]=1;for (int j=1;j<m;j++) f[mid][j]=0;
        g[mid+1][0]=1;for (int j=1;j<m;j++) g[mid+1][j]=0;
        f[mid][a[mid]]++;g[mid+1][a[mid+1]]++;
        for (int i=mid-1;i>=l;i--) for (int j=0;j<m;j++)
            f[i][j]=(f[i+1][j]+f[i+1][(j-a[i]+m)%m])%P;
        for (int i=mid+2;i<=r;i++) for (int j=0;j<m;j++)
            g[i][j]=(g[i-1][j]+g[i-1][(j-a[i]+m)%m])%P;
        for (int i=cl;i<=cr;i++) for (int j=0;j<m;j++)
            s[p[i].d]=(s[p[i].d]+1ll*f[p[i].l][j]*g[p[i].r][(m-j)%m]%P)%P;
    }
    int main(){
        n=R();m=R();for (int i=1;i<=n;i++) a[i]=R()%m;
        q=R();for (int i=1;i<=q;i++) p[i].l=R(),p[i].r=R(),p[i].d=i;
        solve(1,n,1,q);
        for (int i=1;i<=q;i++) printf("%d
    ",s[i]);
        return 0;
    }
    

    T3 4021: 西行妖下(yuyuko)

    题目描述

    幽幽子站在西行妖下,她需要解封西行妖最后的力量。
    西行妖可以当作一个有n 个点的树,每个点都有一些符文,初始每个点符文个数为1。
    幽幽子可以施展魔法,将符文随机移动,来解封封印。每个点上的符文可以看作是一个1~m 的排列,原本的状态为1,2,3,4,……,m 按顺序排列(m 为符文的个数)。想要解封一个点上的封印,要求排列中对于任意的i,pi !=i。幽幽子每次的魔法效果是随机形成一个排列,尝试能否解除封印。
    幽幽子每次会走过一条路径,从s 到t,对每个点施展一次魔法,并询问能解封的点的期望个数。
    现在有Q 次操作:
    Add s t x 在s 到t 的路径上每个点加x 个新的符文。
    Multi s t x 在s 到t 的路径上,每个点符文个数*x。
    Query s t 求从s 到t 解封点的期望个数是多少。
    (注意:每次Query 操作是独立的,即前一次Query 中施展的魔法在Query 结束时被立即撤销,所有走过的路径上点的符文排列变为p i=i,对后续操作不产生影响)

    题解

    来自百度百科的错排详情
    可以把期望值看成错排方案数/排列数
    因为错排方案数为n![1/0!1/1!+1/2!1/3!+1/4!+...+(1)n/n!]n! ·[1/0!-1/1!+1/2!-1/3!+1/4!+...+(-1)^n/n!]
    排列数为n!n!,所以期望值为1/0!1/1!+1/2!1/3!+1/4!+...+(1)n/n!1/0!-1/1!+1/2!-1/3!+1/4!+...+(-1)^n/n!
    当n很大的时候约等于1/e,所以我们只需要求出当n不超过20时的期望值,超过20的当做20来做,然后可以区间修改啦
    其实因为每个数修改得不会超过20,所以我们可以直接单点修改就好了
    具体见代码

    #include <bits/stdc++.h>
    #define Ls k<<1
    #define Rs Ls|1
    #define db double
    #define I inline
    #define E register
    using namespace std;
    const int N=80005;
    int tt,t,n,q,id[N],head[N],V[N*2],nex[N*2],fa[N],son[N],sz[N],top[N],dep[N];
    struct T{db p;int w;}a[N*4];char str[7];db F[21],f[21],jc[21];
    I void add(E int u,E int v){V[++t]=v;nex[t]=head[u];head[u]=t;}
    I void dfs1(E int x,E int fat,E int deep){
        fa[x]=fat;dep[x]=deep;sz[x]=1;
        for (int i=head[x];i;i=nex[i]){
            if (V[i]==fat) continue;
            dfs1(V[i],x,deep+1);sz[x]+=sz[V[i]];
            if (sz[V[i]]>sz[son[x]]) son[x]=V[i];
        }
    }
    I void dfs2(E int x,E int tp){
        top[x]=tp;id[x]=++tt;
        if (son[x]) dfs2(son[x],tp);
        for (E int i=head[x];i;i=nex[i])
            if (V[i]^fa[x] && V[i]^son[x])
                dfs2(V[i],V[i]);
    }
    I void build(E int k,E int l,E int r){
        a[k].w=1;a[k].p=0.0;if (l==r) return;
        int mid=l+r>>1;build(Ls,l,mid);
        build(Rs,mid+1,r);
    }
    I void update(E int k,E int l,E int r,E int L,E int R,E int v,E bool ty){
        if (l==r){
            if (ty) a[k].w=min(20,a[k].w+v);
            else a[k].w=min(20,a[k].w*v);
            a[k].p=F[a[k].w];return;
        }
        int mid=l+r>>1;
        if (mid>=L && a[Ls].w<20) update(Ls,l,mid,L,R,v,ty);
        if (mid<R && a[Rs].w<20) update(Rs,mid+1,r,L,R,v,ty);
        a[k].w=min(a[Ls].w,a[Rs].w);a[k].p=a[Ls].p+a[Rs].p;
    }
    I void update_chain(E int x,E int y,E bool ty,E int v){
        while(top[x]!=top[y]){
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,1,n,id[top[x]],id[x],v,ty);x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        update(1,1,n,id[x],id[y],v,ty);
    }
    I db query(E int k,E int l,E int r,E int L,E int R){
        if (L<=l && r<=R) return a[k].p;
        int mid=l+r>>1;
        if (mid<L) return query(Rs,mid+1,r,L,R);
        if (mid>=R) return query(Ls,l,mid,L,R);
        return query(Ls,l,mid,L,R)+query(Rs,mid+1,r,L,R);
    }
    I void query_chain(E int x,E int y){
        db j=0.0;
        while(top[x]!=top[y]){
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            j=j+query(1,1,n,id[top[x]],id[x]);x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        printf("%.1lf
    ",j+query(1,1,n,id[x],id[y]));
    }
    int main(){
        f[0]=jc[0]=jc[1]=1.0;f[1]=0.0;
        for (int i=2;i<21;i++)
            f[i]=1.0*(i-1)*(f[i-1]+f[i-2]),
            jc[i]=1.0*i*jc[i-1],F[i]=f[i]/jc[i];
        scanf("%d",&n);
        for (E int u,v,i=1;i<n;i++)
            scanf("%d%d",&u,&v),add(u,v),add(v,u);
        dfs1(1,0,1);dfs2(1,1);build(1,1,n);
        for (scanf("%d",&q);q--;){
            scanf("%s",str);int x,y,z;
            if (str[0]=='A'){
                scanf("%d%d%d",&x,&y,&z);
                if (z) update_chain(x,y,1,z);
            }
            else if (str[0]=='M'){
                scanf("%d%d%d",&x,&y,&z);
                if (z>1) update_chain(x,y,0,z);
            }
            else scanf("%d%d",&x,&y),query_chain(x,y);
        }
        return 0;
    }
    
  • 相关阅读:
    Ximarin.Android 百度地图
    利用Chrome浏览器 保存网页成PDF
    SQL 笔记
    windows server 2008 r2 IIS PHP
    自动化分页,HTML代码控制 思想
    simple
    testtitle
    PyQt5中中文问题的不完全解决
    ubuntu下搭建python2.7+PyQt5并实现一个小词典
    opensuse安装深度截图,深度影音和深度播放器
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10544712.html
Copyright © 2011-2022 走看看