zoukankan      html  css  js  c++  java
  • 7月13日考试 题解(DFS序+期望+线段树优化建图)

    T1 sign

    题目大意:给出一棵 N 个节点的树,求所有起点为叶节点的有向路径,其 上每一条边权值和的和。N<=10000

    水题。考试的时候毒瘤出题人(学长orz)把读入顺序改了一下,于是很多人爆零(包括我QAQ。

    先dfs序把以$i$为根的子树大小$size[i]$和所含叶子结点个数$s[i]$求出。考虑每条边对答案的贡献。

      1.子树里的叶子结点往外走,这一部分的贡献为$s[i]*(n-size[i])*dis$

      2.子树外的叶子结点往里走,这一部分的贡献为$(sum-s[i])*size[i]*dis$,$sum$指叶子结点个数。

    然后枚举边累加就好。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int n,ans,du[100005],size[100005],sum,root,ss[100005],tot;
    int head[200005],cnt;
    struct node
    {
        int next,to,dis;
    }edge[200005];
    struct edge
    {
        int from,to,dis;
    }a[100005];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to,int dis)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        edge[cnt].dis=dis;
        head[from]=cnt;
    }
    inline void dfs(int now,int fa)
    {
        size[now]=1;
        if (du[now]==1) ss[now]=1;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (to==fa) continue;
            a[++tot].from=now,a[tot].to=to,a[tot].dis=edge[i].dis;
            dfs(to,now);
            size[now]+=size[to];
            ss[now]+=ss[to];
        }
    }
    signed main()
    {
        n=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            add(y,z,x);add(z,y,x);du[z]++;du[y]++;
        }
        for (int i=1;i<=n;i++)
        {
            if (du[i]>1) root=i;
            else sum++;
        }
        dfs(root,0);
        for (int i=1;i<n;i++) 
            ans+=ss[a[i].to]*(n-size[a[i].to])*a[i].dis+size[a[i].to]*(sum-ss[a[i].to])*a[i].dis;
        printf("%lld",ans);
        return 0;
    }

    T2 map

    题目大意:给定一张含有$n$个点的无向完全图,从$1$号点出发,每秒随机走一条边。$q$次询问,每次询问$t_i$秒时在点$1$的概率。

    对于60%的数据,$n,q,tleq 10^5$

    对于100%的数据,$n,q,tleq 10^{18}$

    60分的很好想。设$f[i]$表示第$i$秒时在点$1$的概率,$g[i]$表示第$i$秒时不在点$1$的概率。易得到:

    $f[i]=g[i-1]*frac{1}{n-1}*(n-1)=g[i-1]$

    $g[i]=f[i-1]*frac{1}{n-1}+g[i-1]*frac{n-2}{n-1}$

    然后考试的时候就想到这里……60pts。正解只需要再往下推一步。

    变换一下形式:$g[i]=g[i-2]*frac{1}{n-1}+g[i-1]*frac{n-2}{n-1}$

    移项,得到:$g[i]-g[i-1]=-frac{1}{n-1}*(g[i-1]-g[i-2])$

    然后就是等比数列化简,得到通项公式:$g[i]=frac{(n-1)^i-(-1)^i}{n*(n-1)^{i-1}},f[i]=frac{(n-1)^{i-1}-(-1)^i}{n*(n-1)^{i-1}}$

    最后快速幂求逆元就好。注意要$n$要模$mod$。时间复杂度$O(qlog n)$。

    代码:

    #include<bits/stdc++.h>
    #define int unsigned long long
    using namespace std;
    const int mod=998244353;
    int n,t,q;
    inline int qpow(int x,int y)
    {
        int res=1;x%=mod;
        while(y>0){
            if (y%2==1) res=res*x%mod;res%=mod;
            x=x*x%mod;
            y>>=1;
        }
        return res%mod;
    }
    signed main()
    {
        scanf("%lld%lld",&n,&q);n%=mod;
        while(q--)
        {
            scanf("%lld",&t);
            if (t==0){
                printf("1
    ");
                continue;
            }
            int x=qpow(n-1,t-1)%mod;
            if (t&1) printf("%lld
    ",((x-1)%mod*qpow(n*x,mod-2)%mod)%mod);
            else printf("%lld
    ",((x+1)%mod*qpow(x*n,mod-2)%mod)%mod);
        }
        return 0;
    }

    T3 【PA2011】Journeys

    题目链接

    题目大意:点从$1-n$标号。给定$[l1,r1]$和$[l2,r2]$,表示$[l1,r1]$内的点与$[l2,r2]$内任意一点都有长度为$1$的边。求点$s$的单源最短路径。

    线段树优化建图模板题。

    建立一棵入树,一棵出树,对于每次连边建两个虚点,在其间连一条权为1的边;然后从出树连出来,连进去入树,边权均为0。注意边是双向的,因此需要做两遍。

    最短路不需要 Dijkstra,只需要 01BFS。时间复杂度$O(nlog n)$。

    关于各种图的优化技巧可以看大佬的博客orz

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,S,head[8000005],cnt,tot,dis[4000005],ls[4000005],rs[4000005];
    struct edge
    {
        int next,to,dis;
    }edge[8000005];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void addedge(int from,int to,int dis)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        edge[cnt].dis=dis;
        head[from]=cnt;
    }
    void Build(int &p,int &q,int l,int r) {
        if(l==r){
            p=l,q=l;
            return ;
        }
        if(!p)p=++tot;
        if(!q)q=++tot;
        int mid=(l+r)/2;
        Build(ls[p],ls[q],l,mid),addedge(ls[p],p,0),addedge(q,ls[q],0);
        Build(rs[p],rs[q],mid+1,r),addedge(rs[p],p,0),addedge(q,rs[q],0);
    }
    void Add(int p,int l,int r,int x,int y,int z,int flag) {
        if(x<=l&&r<=y) {
            if(flag)addedge(z,p,0);
            else addedge(p,z,0);
            return ;
        }
        int mid=(l+r)/2;
        if(x<=mid)Add(ls[p],l,mid,x,y,z,flag);
        if(mid<y)Add(rs[p],mid+1,r,x,y,z,flag);
    }
    void Dijkstra() {
        memset(dis,0x3f,sizeof(dis));
        deque<int> q;
        dis[S]=0;
        q.push_back(S);
        while(!q.empty()) {
            int now=q.front();
            q.pop_front();
            for(int i=head[now]; i; i=edge[i].next) {
                int y=edge[i].to,v=edge[i].dis;
                if(dis[y]>dis[now]+v) {
                    dis[y]=dis[now]+v;
                    if(v)q.push_back(y);
                    else q.push_front(y);
                }
            }
        }
        for(int i=1;i<=n;i++)printf("%d
    ",dis[i]);
    }
    int main()
    {
        n=read(),m=read(),S=read(),tot=n;
        int root1=0,root2=0;
        Build(root1,root2,1,n);
        while(m--){
            int x=read(),y=read(),z=read(),w=read(),a=++tot,b=++tot;
            addedge(a,b,1);
            Add(root1,1,n,x,y,a,0);
            Add(root2,1,n,z,w,b,1);
            a=++tot,b=++tot;
            addedge(a,b,1);
            Add(root1,1,n,z,w,a,0);
            Add(root2,1,n,x,y,b,1);
        }    
        Dijkstra();
        return 0;
    }
  • 相关阅读:
    中国剩余定理及拓展
    20191128-1 总结
    获取动态图
    弹球游戏设计
    作业要求 20191121-1 每周例行报告
    作业要求 20191114-1 每周例行报告
    对现组内成员的感谢
    作业要求 20191107-1 每周例行报告
    20191031-1 每周例行报告
    作业要求 20191024-1每周例行报告
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13295070.html
Copyright © 2011-2022 走看看