• 2016多校1


    HDU 5723 A  t 组样例 n个点m条边

    然后m条无向边 

    a  b  w

    求他的最小生成树的  花费 

    然后求  每2个点的花费的期望

    先跑一个最小生成树  

    然后呢   要求期望 先要求出一个 总体花费 然后 /(n*(n-1)/2)

    那么怎么求花费呢     比如说样例     1 - 2 - 3 - 4

                                                      1   2  3

                    用dfs 维护子树的点的数目

                  那么这条边的贡献 就是num[孩子] *(n-num[孩子]) *w(边)

                               上面             下面

    最后结果     

    #include<stdio.h>
    #include<algorithm>
    #include<stdlib.h>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<stack>
    
    using namespace std;
    
    #define ll   __int64
    #define MAXN  100010
    #define inf  1000000000
    #define mod 1000000007
    struct edg
    {
        int fr,to,w,next;
    }edge[1000010],edg1[2000010];
    int z[MAXN];
    bool cmp(edg a,edg b)
    {
        return a.w<b.w;
    }
    int find1(int a)
    {
        if(z[a]==a)
            return a;
        else
        {
            int b=find1(z[a]);
            return z[a]=b;
        }
    }
    int cnt;
    int head[MAXN];
    void add(int u,int v,int w)
    {
        edg1[cnt].to=v;
        edg1[cnt].w=w;
        edg1[cnt].next=head[u];
        head[u]=cnt++;
    }
    int sz[MAXN];
    double ans1;
    int n,m;
    void dfs(int u,int fa)
    {
        sz[u]=1;
        for(int i=head[u];i!=-1;i=edg1[i].next)
        {
    
            int v=edg1[i].to;
    
            if(v==fa)
                continue;
           // printf("%d
    ",v);
            dfs(v,u);
            sz[u]=sz[u]+sz[v];
            ans1=ans1+ (double)sz[v]*(n-sz[v])*edg1[i].w;
            //printf("%d %lf
    ",v,ans1);
        }
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
    
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                z[i]=i;
            for(int i=1;i<=m;i++)
                scanf("%d%d%d",&edge[i].fr,&edge[i].to,&edge[i].w);
            sort(edge+1,edge+m+1,cmp);
            ll ans=0;
            cnt=0;
            memset(head,-1,sizeof(head));
            int c1=0;
            for(int i=1;i<=m;i++)
            {
                int fa,fb;
                fa=find1(edge[i].fr);
                fb=find1(edge[i].to);
                if(fa!=fb)
                {
                    c1++;
                     z[fa]=fb;
                     ans+=edge[i].w;
                     add(edge[i].fr,edge[i].to,edge[i].w);
                     add(edge[i].to,edge[i].fr,edge[i].w);
                }
                if(c1==n-1)
                    break;
            }
            printf("%I64d ",ans);
            ans1=0;
            dfs(1,0);
            printf("%.2lf
    ",ans1/n/(n-1)*2);
        }
        return 0;
    }
    View Code

    HDU 5724 B

    t 个样例

    n 行 

    然后n行

    m  m个数字

    代表开始的位置

    一次只能像右 走1个能跳过去  不能重叠  最多走到20

    Alice 先走  他能营的话  YES否则N0

    显然多行的话就是个尼姆博弈

    那么一行呢 

    看代码 

    #include<stdio.h>
    #include<algorithm>
    #include<stdlib.h>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<iterator>
    #include<stack>
    
    using namespace std;
    
    #define ll   __int64
    #define MAXN  100010
    #define inf  1000000000
    #define mod 1000000007
    bool vis[25];
    int  sg[1<<21];
    
    int get(int a)
    {
        memset(vis,0,sizeof(vis));
        for(int i=20;i>=0;i--)  
        {
            if(a&(1<<i))  // 第i    是1
            {
                int t=a;
                for(int j=i-1;j>=0;j--) 
                {
                    if(!(a&(1<<j))) //走到0的
                    {
                        t^=(1<<i)^(1<<j); //把i 这个1去掉  j 这个1加上
                        vis[sg[t]]=1;     //这个位子能走到
                        break;
                    }
                }
    
            }
        }
        for(int i=0;i<=20;i++)  //最多能走到20种  所以..
            if(!vis[i])
                return i;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        for(int i=0;i<(1<<21);i++) //预处理出每个状态的sg
            sg[i]=get(i);
        while(t--)
        {
            int n;
            scanf("%d",&n);
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                int m;
                scanf("%d",&m);
                int now=0;
                for(int j=1;j<=m;j++)
                {
                    int a;
                    scanf("%d",&a);
                    now|=1<<(20-a);  //这边每个就上去1
                }
                ans ^=sg[now];
            }
            if(ans==0)
                printf("NO
    ");
            else
                printf("YES
    ");
        }
        return 0;
    }

    D hdu 5726

    t 组样例  n 个数

    M 个查询

    问所有区间里能和这个区间gcd一样的数目  长度为1的也算

    输出gcd和数目

    显然先要线段树维护一下gcd

    然后暴力统计一下到z[i]的gcd的数目 ans[a]=b   代表gcd为a的区间数目为b

    m1 是到z[i] 的gcd数目   m2临时的  ans  结果

    #include<stdio.h>
    #include<algorithm>
    #include<stdlib.h>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<iterator>
    #include<stack>
    
    using namespace std;
    
    #define ll   __int64
    #define MAXN  100010
    #define inf  1000000000
    #define mod 1000000007
    struct node
    {
        int l,r,w;
    }tree[MAXN<<2];
    int z[MAXN];
    int gcd(int a,int b)
    {
        return b?gcd(b,a%b):a;
    }
    void push_up(int a)
    {
        tree[a].w=gcd(tree[a<<1].w,tree[a<<1|1].w);
    }
    void Build(int l,int r,int a)
    {
        tree[a].l=l;
        tree[a].r=r;
        if(l==r)
        {
            tree[a].w=z[l];
            return ;
        }
        int mid=(l+r)>>1;
        Build(l,mid,a<<1);
        Build(mid+1,r,a<<1|1);
        push_up(a);
    }
    int Ques(int l,int r,int l1,int r1,int a)
    {
        if(l1<=l&&r<=r1)
        {
            return tree[a].w;
        }
        int ans=0;
        int mid=(l+r)>>1;
        if(l1<=mid)
            ans = gcd(ans,Ques(l,mid,l1,r1,a<<1));
        if(r1>mid)
            ans = gcd(ans,Ques(mid+1,r,l1,r1,a<<1|1));
        return ans;
    }
    map<int,ll>ans,m1,m2;
    
    int main()
    {
        int t,ca;
        scanf("%d",&t);
        ca=1;
        while(t--)
        {
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%d",&z[i]);
            Build(1,n,1);
            printf("Case #%d:
    ",ca++);
            ans.clear();
            m1.clear();
            m2.clear();
            m1[z[1]]++;
            ans[z[1]]++;
            for(int i=2;i<=n;i++)
            {
                int now=z[i];
                m2[now]++;
                ans[now]++;
                for(map<int,ll>::iterator it=m1.begin();it!=m1.end();it++)
                {
                    int g=gcd(now,it->first);
                    m2[g]+=it->second;
                    ans[g]+=it->second;
                }
                m1.clear();
                for(map<int,ll>::iterator it=m2.begin();it!=m2.end();it++)
                {
                    m1[it->first]=it->second;
                }
                m2.clear();
            }
            int m;
            scanf("%d",&m);
            while(m--)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                int tmp=Ques(1,n,l,r,1);
                printf("%d %I64d
    ",tmp,ans[tmp]);
            }
        }
        return 0;
    }
    View Code

               

  • 相关阅读:
    UVA10763交换学生
    UVA10763交换学生
    UVA10391复合词
    UVA10391复合词
    UVA10125和集
    UVA10125和集
    POJ3762 时间段用k次
    POJ3762 时间段用k次
    Win64 驱动内核编程-11.回调监控进线程句柄操作
    Win64 驱动内核编程-11.回调监控进线程句柄操作
  • 原文地址:https://www.cnblogs.com/cherryMJY/p/6613163.html
Copyright © 2020-2023  润新知