zoukankan      html  css  js  c++  java
  • 2016 MultiUniversity Training Contest 1

    A.Abandoned country

    构建最小生成树,然后每条边的权值乘以两边的点数之积。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn = 1e5+5;
    int n,m;
    struct Edge{
        int u,v,w;
    };
    Edge edge[10*maxn];
    vector<Edge> g[maxn];
    int in[maxn];
    int pre[maxn];
    int vis[maxn];
    typedef long long ll;
    bool cmp(Edge A,Edge B)
    {
        return A.w<B.w;
    }
    ll sum = 0;
    double sum2 = 0;
    int Find(int x){return pre[x] == x ? x : pre[x] = Find(pre[x]);}
    
    int Merge(int x,int y)
    {
        int fx = Find(x);
        int fy = Find(y);
        if(fx != fy)
        {
            pre[fx] = fy;
            return 1;
        }
        return 0;
    }
    void Kruskal()
    {
        for(int i = 1; i<=m; i++)
        {
            if(Merge(edge[i].u,edge[i].v))
            {
                sum += edge[i].w;
                g[edge[i].u].push_back((Edge){edge[i].u,edge[i].v,edge[i].w});
                g[edge[i].v].push_back((Edge){edge[i].v,edge[i].u,edge[i].w});
                in[edge[i].u]++;
                in[edge[i].v]++;
            }
        }
    }
    void inin()
    {
        for(int i = 1; i<=n; i++)
        {
            pre[i] = i;
            in[i] = 0;
            g[i].clear();
            vis[i] = 0;
        }
    }
    int dfs(int x)
    {
        vis[x] = 1;
        int num = 1;
        for(int i = 0; i<g[x].size(); i++)
        {
            Edge cur = g[x][i];
            if(vis[cur.v]) continue;
            if(in[cur.v]==1)
            {
                sum2 += (double)cur.w*(n-1);
                num += 1;
                continue;
            }
            int ver = dfs(cur.v);
            sum2 += (double)cur.w*ver*(n-ver);
            num += ver;
        }
        return num;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d",&n,&m);
            inin();
           for(int i = 1; i<=m; i++)
           {
               scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
           }
           sort(edge+1,edge+m+1,cmp);
           sum = 0;
           Kruskal();
           sum2 = 0;
           int i = 0;
           dfs(1);
           printf("%I64d %.2lf\n",sum,sum2*2/n/(n-1));
        }
        return 0;
    }
    /*
    421
    7 6
    1 2 1
    2 3 2
    3 4 3
    3 5 4
    3 6 5
    3 7 6
    */
    卷珠帘

    D.GCD

    RMQ-ST预处理出gcd,复杂度n*logn*gcd.不过查询复杂度为log*gcd.

    第二问枚举起点,对每个起点,gcd分段递减,对每一段二分出段的尾部,然后这段的gcd值都相同,用map记录,每个起点最多logn段。复杂度n*logn*logn*gcd。查询logn

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <map>
    using namespace std;
    const int maxn = 1e5+5;
    int n;
    int cnt[maxn];
    int M[maxn][20];
    map<int,long long> g;
    int gcd(int a,int b)
    {
        return b == 0 ? a : gcd(b,a%b);
    }
    void inin()
    {
        for(int i = 1; i<=n; i++) M[i][0] = cnt[i];
        for(int j = 1; (1 << j) <= n; j++)
            for(int i = 1; (i + (1 << j)-1) <= n; i++)
            M[i][j] = gcd( M[i][j-1] , M[i + (1 << (j-1))][j-1]);
    }
    int query(int l,int r)
    {
        int k = 0;
        while((1 << (k+1))<=(r-l+1)) k++; //r-2^k+1>=l+2^k
        return gcd(M[l][k],M[r-(1 << k)+1][k]);
    }
    int binary(int s,int head,int g)
    {
        int L = head;
        int R = n;
        int result = head;
        while(L<=R)
        {
            int mid = (L+R)/2;
            if(query(s,mid)==g)
            {
                result = mid;
                L = mid+1;
            }
            else R = mid-1;
        }
        return result;
    }
    void pre()
    {
        g.clear();
        for(int i = 1; i<=n; i++)
        {
            int head = i;
            while(head<=n)
            {
                int Gcd = query(i,head);
                int tail = binary(i,head,Gcd);
                g[Gcd] += tail-head+1;
                head = tail+1;
            }
        }
    }
    int main()
    {
        int t,kase = 0;
        cin>>t;
        while(t--)
        {
            printf("Case #%d:\n",++kase);
            scanf("%d",&n);
            for(int i = 1; i<=n; i++)
            {
                scanf("%d",&cnt[i]);
            }
            inin();
            pre();
            int q,l,r;
            cin>>q;
            for(int i = 1; i<=q; i++)
            {
                scanf("%d %d",&l,&r);
                int gg = query(l,r);
                printf("%d %I64d\n",gg,g[gg]);
            }
        }
        return 0;
    }
    卷珠帘
  • 相关阅读:
    jython 访问数据库的方法
    Server 2008安装FTP的简单教程
    如何实现Android重启应用程序代码 ?
    android 应用程序自适应屏幕大小
    Android Dialog用法
    2008Server错误
    7种形式的Android Dialog使用举例
    ADB使用方法
    调用手机震动
    android小记之FTP文件上传
  • 原文地址:https://www.cnblogs.com/littlepear/p/5688537.html
Copyright © 2011-2022 走看看