zoukankan      html  css  js  c++  java
  • UESTC 2014 Summer Training #16 Div.2

      虽然被刷了还是要继续战斗下去嗯...就是基础不好,难度相对较大

    A.SPOJ AMR10A

      点是顺时针给出的,可以在图上画画(脑补也行),连线x-a,x-b(x为选定的一个点,比如第一个点),就把所求面积分成了四部分,a-b左边部分是较容易求出来的,

    三角形面积是直接可求,另外两个多边形面积是可以预处理出来的(多个三角形面积和)

      反正我是沒想出來...看題解也理解半天,多邊形面積转化为三角形面积和 嗯嗯

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    
    using namespace std;
    
    const int maxn = 50000+50;
    
    struct Point{
        long long x, y;
    
        Point() {}
    
        Point(long long x, long long y) {
            this->x = x;    this->y = y;
        }
    
    }a[maxn];
    
    int N, Q;
    long long sum[maxn];
    
    long long getArea(Point a, Point b, Point c)
    {
        return abs( (c.y-a.y)*(b.x-a.x)-(b.y-a.y)*(c.x-a.x) );
    }
    
    int main()
    {
    #ifdef LOCAL
        freopen("A.in", "r", stdin);
    #endif
        scanf("%d%d", &N, &Q);
        for(int i = 1; i <= N; i++) {
            long long x, y;
            scanf("%lld%lld", &x, &y);
            a[i] = Point(x, y);
        }
        for(int i = 3; i <= N; i++)
            sum[i] = sum[i-1] + getArea(a[1], a[i-1], a[i]);
        while(Q--) {
            int u, v;
            scanf("%d%d", &u, &v);
            u++;    v++;
            if(v < u)    swap(u, v);
            long long ans = sum[N] - sum[v] + getArea(a[1], a[u], a[v]) + sum[u];
            ans = min(ans, sum[N]-ans);
            if(ans%2 != 0)    printf("%lld.5
    ", ans/2);
            else    printf("%lld.0
    ", ans/2);
        }
        return 0;
    }

    C.SPOJ AMR11C

      可以转化为二分图的最大带权匹配问题,连边+KM

      连边朴素的dfs是会挂掉的,2^25,这里介绍一个方法解决这类求子集和的问题,meet-in-the-middle algorithm

      http://www-ti.informatik.uni-tuebingen.de/~reinhard/krypto/English/4.5.1.e.html

      大致意思是先预处理出前一半元素能组合出的数,2^13个,并且排序,然后枚举后一半能组合出的数s2,二分查找sum-s2是否存在,时间复杂度是可以接受的,具体看以上链接

      不过KM算法我不会呢...先扔这里吧

    F.SPOJ AMR10F

      水题

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    
    using namespace std;
    
    int T, N, A, D;
    
    int main()
    {
        cin >> T;
        while(T--) {
            cin >> N >> A >> D;
            cout << (2*A+(N-1)*D)*N/2 << endl;
        }
        return 0;
    }

    G.SPOJ AMR10G

      队友搞出来的...我没怎么思考,就是排序后,检查每一个区间的极差,算有点贪心,每次选取连续的k个

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 20000+50;
    const int inf = ~0u >> 1;
    
    int T, k, n;
    int h[maxn];
    
    int main()
    {
    #ifdef LOCAL
        freopen("G.in", "r", stdin);
    #endif
        scanf("%d", &T);
        while(T--) {
            scanf("%d%d", &n, &k);
            for(int i = 0; i < n; i++)
                scanf("%d", h+i);
            sort(h, h+n);
            int ans = inf;
            for(int i = 0; i+k <= n; i++)
                ans = min(h[i+k-1]-h[i], ans);
            printf("%d
    ", ans);
        }
        return 0;
    }

    H.SPOJ AMR10H

      贪心的做法,考虑最小的两个概率一定要放在最两边(选择最两边时,耗时最大)...不要问我为什么= =

      最后算下gcd除去就可以了  ps:  gcd(a,0) = a

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 40;
    
    int T, n, a, b, c;
    int p[maxn], arranged[maxn];
    
    int gcd(int a, int b)
    {
        return b == 0 ? a: gcd(b, a%b);
    }
    
    int main()
    {
    #ifdef LOCAL
        freopen("H.in", "r", stdin);
    #endif
        scanf("%d", &T);
        while(T--) {
            scanf("%d%d%d%d", &n, &a, &b, &c);
            for(int i = 0; i < n; i++)
                scanf("%d", p+i);
            sort(p, p+n);
            int front = 0, rear = n-1;
            for(int i = 0; i < n; i++)
                arranged[i%2?rear--:front++] = p[i];
            int ans = 0;
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    ans += arranged[i]*arranged[j]*((i-j)*(i-j)*a+b*abs(i-j)+c);
            printf("%d/%d
    ", ans/gcd(ans, 10000), 10000/gcd(10000, ans));
        }
        return 0;
    }

    I.SPOJ AMR10I

      这道题我是无论如何也想不到这样优化的...

      N=a1+a2+...+an,  P=a1a2...an

      a1...an都能唯一分解为素数相乘,因此P一定是2~N的素数乘积,似乎通过一个素数表来dfs

      现在要考虑另一点(很多blog没有指出) 最原始的办法是dfs 1~N 现在我们dfs这个素数表,是否覆盖了所有的情况呢?

      事实上2,3的组合就能覆盖2~N的所有数,即使用素数替换之前dfs的数

      例如10 = 6+4  原始的做法会去 dfs 4 6  而现在dfs  2 2 2 3 素数的组合

      想了半天其实自己也不是很理解...

      PS:第一次使用set 资料给出基本操作都是O(logn)!!

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <set>
    
    using namespace std;
    
    const int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71};  
    
    int T, N, P;
    set<long long> cnt;
    
    void dfs(int x, int r, long long p)
    {
        if(x >= 20)    return;
        cnt.insert(p);
    //    cout << "insert " << p <<endl;
        if(r < prime[x])    return;
        dfs(x, r-prime[x], p*prime[x]%P);
        //if(r < prime[x+1])    return;
        dfs(x+1, r, p);
    }
    
    int main()
    {
    #ifdef LOCAL
        freopen("I.in", "r", stdin);
    #endif
        scanf("%d", &T);
        while(T--) {
            scanf("%d%d", &N, &P);
            cnt.clear();
            dfs(0, N, 1ll);    
            printf("%d
    ", cnt.size());
        }
        return 0;
    }
  • 相关阅读:
    设计模式学习——前言和目录
    模板颜色搭配
    win7、xp下Meclipse SVN用户名修改
    JS编码解码
    用Javascript进行HTML转义(分享)
    打印异常信息
    lucene 抛出的异常(分享)
    SQL语句优化(分享)
    Java集群之session共享解决方案
    VUE中返回上一页
  • 原文地址:https://www.cnblogs.com/gemmeg/p/3898726.html
Copyright © 2011-2022 走看看