zoukankan      html  css  js  c++  java
  • Mango Weekly Training Round #6 解题报告

    比赛链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=41856#overview

     

    A.多种解法。可以dfs倒序染色,如mathlover神的代码:

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int x1,y1,x2,y2;
        bool color;
    } a[5010];
    int n,m;
    int ans;
    void dfs(int x1,int y1,int x2,int y2,bool color,int num)
    {
        if(num==m)
        {
            if(color)
                ans+=(y2-y1+1)*(x2-x1+1);
            return;
        }
        if(x1>a[num].x2||x2<a[num].x1||y2<a[num].y1||y1>a[num].y2)
        {
            dfs(x1,y1,x2,y2,color,num+1);
            return;
        }
        if(x1<a[num].x1)
            dfs(x1,y1,a[num].x1-1,y2,color,num+1);
        if(x2>a[num].x2)
            dfs(a[num].x2+1,y1,x2,y2,color,num+1);
        if(y1<a[num].y1)
            dfs(max(x1,a[num].x1),y1,min(x2,a[num].x2),a[num].y1-1,color,num+1);
        if(y2>a[num].y2)
            dfs(max(x1,a[num].x1),a[num].y2+1,min(x2,a[num].x2),y2,color,num+1);
    }
    int main()
    {
        char temp;
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=0; i<m; ++i)
            {
                scanf("%d %d %d %d %c",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2,&temp);
                a[i].color=(temp=='b');
                if(a[i].x1>a[i].x2)
                    swap(a[i].x1,a[i].x2);
                if(a[i].y1>a[i].y2)
                    swap(a[i].y1,a[i].y2);
            }
            ans=0;
            for(int i=m-1; i>=0; --i)
                dfs(a[i].x1,a[i].y1,a[i].x2,a[i].y2,a[i].color,i+1);
            printf("%d
    ",n*n-ans);
        }
    }
    //GL && HF
    View Code

    但是暴力貌似也可以过,上暴力代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 1007
    
    int a[N][N];
    
    int main()
    {
        int n,m,i,j,tag,cnt;
        int x1,x2,y1,y2;
        char ss[4];
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(a,0,sizeof(a));
            cnt = 0;
            while(m--)
            {
                scanf("%d%d%d%d%s",&x1,&y1,&x2,&y2,ss);
                int maxx = max(x1,x2);
                int maxy = max(y1,y2);
                int minx = min(x1,x2);
                int miny = min(y1,y2);
                if(ss[0] == 'b')
                    tag = 1;
                else
                    tag = 0;
                for(i=minx;i<=maxx;i++)
                    for(j=miny;j<=maxy;j++)
                        a[i][j] = tag;
            }
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=n;j++)
                    cnt += 1-a[i][j];
            }
            printf("%d
    ",cnt);
        }
        return 0;
    }
    View Code

     

    B.数学方法(等我弄懂了再写一个容易懂的)

     

    C.生成排列,自行询问或找题解

     

    D.归并排序或者树状数组求逆序对数

    这个应该是非常经典的经典题,用归并排序求逆序数。

    归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
    算法描述
    归并操作的工作原理如下:

      1. 申请空间,归并排序需要一个辅助数组,大小和要排序的数组相同。
      2. 若选取的范围内的元素个数大于等于2,则进行分治。
      3. 设定两个指针,最初位置分别为两个已经排序序列的起始位置。
      4. 比较两个指针所指向的元素,选择相对小的元素放入到辅助数组,并移动指针到下一位置。
      5. 重复步骤4直到某一指针达到序列尾。
      6. 将另一序列剩下的所有元素直接复制到辅助数组中。
      7. 将辅助数组中的元素复制到原数组。

    归并排序代码:(By hlove)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    #define maxn 65555
    using namespace std;
    
    int num[maxn],temp[maxn],n;
    
    long long Merge(int low,int mid,int high)
    {
        int i=low,j=mid+1,cnt=low;
        long long count=0;;
        while(i<=mid&&j<=high){
            if(num[i]>num[j]){temp[cnt++]=num[j++];count+=mid-i+1;}
            else temp[cnt++]=num[i++];
        }
        while(i<=mid)temp[cnt++]=num[i++];
        while(j<=high)temp[cnt++]=num[j++];
        for(i=low;i<=high;i++)num[i]=temp[i];
        return count;
    }
    long long mergesort(int low,int high)
    {
        long long cnt=0;
        if(high>low){
            int mid = (high+low)/2;
            cnt+=mergesort(low,mid);
            cnt+=mergesort(mid+1,high);
            cnt+=Merge(low,mid,high);
        }
        return cnt;
    }
    int main()
    {
        while(scanf("%d",&n)==1){
            for(int i=0;i<n;i++){
                scanf("%d",&num[i]);
            }
            printf("%lld
    ",mergesort(0,n-1));
        }
        return 0;
    }
    View Code

    树状数组代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 66007
    
    lll c[N],k[N];
    int n;
    struct node
    {
        lll val;
        int ind;
    }a[N];
    
    int cmp(node ka,node kb)
    {
        return ka.val < kb.val;
    }
    
    lll lowbit(lll x)
    {
        return x&(-x);
    }
    
    void modify(lll x)
    {
        while(x <= n)
        {
            c[x]++;
            x += lowbit(x);
        }
    }
    
    lll sum(lll x)
    {
        lll res = 0;
        while(x > 0)
        {
            res += c[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    int main()
    {
        lll x,cnt;
        int i;
        while(scanf("%d",&n)!=EOF)
        {
            memset(c,0,sizeof(c));
            cnt = 0;
            for(i=1;i<=n;i++)
            {
                scanf("%I64d",&a[i].val);
                a[i].ind = i;
            }
            sort(a+1,a+n+1,cmp);
            lll pre = -1000000,now = 1;
            for(i=1;i<=n;i++)
            {
                if(a[i].val != pre)
                {
                    pre = a[i].val;
                    a[i].val = now++;
                }
                else
                    a[i].val = now-1;
            }
            for(i=1;i<=n;i++)
                k[a[i].ind] = a[i].val;
            for(i=1;i<=n;i++)
            {
                modify(k[i]);
                cnt += i - sum(k[i]);
            }
            printf("%I64d
    ",cnt);
        }
        return 0;
    }
    View Code

    关于树状数组求逆序对数: http://hi.baidu.com/sculiunian/item/2d0c9bd6340396f2785daa71

     

    E.找循环节,一直计算Xi,由于m在1000内,所以到某个时刻总会出现前面已出现的的值,即形成循环节,用con记录Xi何时出现,初始化为-1,con[A] =  0; 计算到Xi时,如果con[Xi]已经出现,说明开始循环了。找出循环起点与循环长度,然后看k在那一段,根据循环找出x[k]..具体键代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 1007
    
    int con[N];
    lll x[N];
    int main()
    {
        lll alpha,beta,gamma,m;
        int k,a;
        while(scanf("%d%I64d%I64d%I64d%I64d%d",&a,&alpha,&beta,&gamma,&m,&k)!=EOF)
        {
            x[0] = a;
            int i = 1;
            int qi,len;
            memset(con,-1,sizeof(con));
            con[a%m] = 0;
            if(k == 0)
            {
                printf("%d
    ",a);
                continue;
            }
            i = 1;
            while(1)
            {
                x[i] = (alpha*x[i-1]*x[i-1] + beta*x[i-1] + gamma)%m;
                if(con[x[i]] == -1)
                    con[x[i]] = i;
                else
                {
                    qi = con[x[i]];
                    len = i-qi;
                    if(k >= qi)
                        k = qi+(k-qi)%len;
                    break;
                }
                i++;
            }
            printf("%I64d
    ",x[k]);
        }
        return 0;
    }
    View Code

     

    F.搜索,自寻题解

     

    G.DP优化

    mathlover代码:

    #include <stdio.h>
    #include<algorithm>
    #define M 105
    #define N 10005
    int n, m,dp[M][M],c[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;++i)
            scanf("%d",&c[i]);
        for (int i=1;i<=n+1;++i)
            for (int j=1;j<m;++j)
            {
                int tmp =(i-j+M)%M;
                dp[i%M][j]=dp[tmp][m-j]+c[i];
                if (j != 1)
                    dp[i%M][j]=std::min(dp[i%M][j],dp[i%M][j-1]);
            }
        printf("%d
    ",dp[(n+1)%M][m-1]);
        return 0;
    }
    View Code

     

    H.大水题。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 1007
    
    int main()
    {
        int p,m,c,k,r,v;
        while(scanf("%d%d%d%d%d%d",&p,&m,&c,&k,&r,&v)!=EOF)
        {
            int res1 = p/k;
            int res2 = m/r;
            int res3 = c/v;
            printf("%d
    ",min(res1,min(res2,res3)));
        }
        return 0;
    }
    View Code

     

    I.网络流,自寻题解:https://www.google.com.hk/#newwindow=1&q=SGU+185&safe=strict

     

    J.题目有点难懂,重点是理解,题目说的合并链子不是直接连上,而是要从别的地方取一个珠子来作为中介来连接两条链子,这样,每次在长度最短的链子中取珠子,说不定就可以减少链子的条数,岂不是可以减少时间。。好,就这么干。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 1007
    
    int a[105];
    
    int main()
    {
        int n,i,x;
        while(scanf("%d",&n)!=EOF)
        {
            for(i=0;i<n;i++)
                scanf("%d",&a[i]);
            sort(a,a+n);
            int head = 0;
            int tail = n-1;
            int step = 0;
            while(head < tail)
            {
                a[head]--;  //最短的链子上的珠子减1
                if(a[head] <= 0)  //这条链没了
                    head++;
                int tmp = a[tail] + a[tail-1] + 1; //合并两条链,加不加1都可以
                a[--tail] = tmp;
                step++;
            }
            printf("%d
    ",step);
        }
        return 0;
    }
    View Code

     

  • 相关阅读:
    Python学习(十六)内置函数,递归
    Python学习(十五)json串使用,不固定参数,关键词参数
    Python学习(十四)常量,局部变量,全局变量
    python学习(十三)函数
    python学习(十二)模块
    Python学习(十一)文件指针,文件操作练习,修改文件
    mongodb聚合
    mongodb
    软件测试需要学习哪些课程
    Jmeter的使用和监控分析
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3590444.html
Copyright © 2011-2022 走看看