2016年 团体程序设计天梯赛 - 模拟赛

此处有目录↑

L1的题太水了,直接模拟即可,就不贴了

L3-2和L3-3没时间写了(估计也不好写吧。。。)

比赛网址:https://www.patest.cn/contests/2016gplt-0

交题网址: https://www.patest.cn/contests/gplt

L2-1. 集合相似度 (排序)

时间限制

400 ms

内存限制

65536 kB

代码长度限制

8000 B

判题程序

Standard

作者

陈越

给定两个整数集合,它们的相似度定义为:Nc/Nt*100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。

输入格式:

输入第一行给出一个正整数N(<=50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(<=104),是集合中元素的个数;然后跟M个[0, 109]区间内的整数。

之后一行给出一个正整数K(<=2000),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。

输出格式:

对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。

输入样例:

3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3

输出样例:

50.00%
33.33%

第一次比较时也用的map,结果最后一组数据超时了

最后排序直接在两个集合扫一边即可

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>

using namespace std;

int n,k,m,xx,a,b;
int cnt[51];
int num[51][10001];
map<int,bool> mp[51];

double getAns(int i,int j) {
    int nc=0,nt=cnt[i]+cnt[j],x=0,y=0;
    while(x<cnt[i]&&y<cnt[j]) {
        if(num[i][x]==num[j][y]) {
            ++nc;
            ++x;
            ++y;
        }
        else if(num[i][x]<num[j][y]) {
            ++x;
        }
        else {
            ++y;
        }
    }
    return 100.0*nc/(nt-nc);
}

int main() {
    while(1==scanf("%d",&n)) {
        for(int i=0;i<n;++i) {
            mp[i].clear();
            cnt[i]=0;
            scanf("%d",&m);
            for(int j=0;j<m;++j) {
                scanf("%d",&xx);
                if(!mp[i][xx]) {
                    num[i][cnt[i]++]=xx;
                    mp[i][xx]=true;
                }
            }
            sort(num[i],num[i]+cnt[i]);
        }
        scanf("%d",&k);
        while(k-->0) {
            scanf("%d%d",&a,&b);
            printf("%.2lf%%\n",getAns(a-1,b-1));
        }
    }
    return 0;
}

L2-2. 树的遍历 (分治)

时间限制

400 ms

内存限制

65536 kB

代码长度限制

8000 B

判题程序

Standard

作者

陈越

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(<=30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2

直接用的以前写的USACO 前序+中序 的代码改的

大致思想就是:每次取一颗子树中,后序遍历的最后一个数(即根),在中序遍历中找到,分成两颗子树,递归进行,直至只有一个数时

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=105;

int n,cnt=1,root;
int inod[35],bacod[35];
int q[35],head,tail;

struct Node {
    int lson,rson;
    int c;
}tr[35];

int dfs(int bl,int br,int il,int ir) {
    if(bl==br) {
        tr[cnt].lson=tr[cnt].rson=-1;
        tr[cnt].c=bacod[br];
        return cnt++;
    }
    for(int i=il;i<=ir;++i) {
        if(bacod[br]==inod[i]) {
            int cur=cnt++;
            tr[cur].lson=tr[cur].rson=-1;
            tr[cur].c=bacod[br];
            if(il<i) {
                tr[cur].lson=dfs(bl,bl+i-il-1,il,i-1);
            }
            if(i<ir) {
                tr[cur].rson=dfs(bl+i-il,br-1,i+1,ir);
            }
            return cur;
        }
    }
    return cnt;
}

void print(int root) {
    printf("%d",tr[root].c);
    int cur;
    head=tail=0;
    if(tr[root].lson!=-1) {
        q[tail++]=tr[root].lson;
    }
    if(tr[root].rson!=-1) {
        q[tail++]=tr[root].rson;
    }

    while(head!=tail) {
        cur=q[head++];
        printf(" %d",tr[cur].c);
        if(tr[cur].lson!=-1) {
            q[tail++]=tr[cur].lson;
        }
        if(tr[cur].rson!=-1) {
            q[tail++]=tr[cur].rson;
        }
    }
    printf("\n");
}

int main() {
    while(1==scanf("%d",&n)) {
        for(int i=0;i<n;++i) {
            scanf("%d",bacod+i);
        }
        for(int i=0;i<n;++i) {
            scanf("%d",inod+i);
        }
        cnt=0;
        print(dfs(0,n-1,0,n-1));
    }
    return 0;
}

L2-3. 家庭房产 (并查集)

时间限制

400 ms

内存限制

65536 kB

代码长度限制

8000 B

判题程序

Standard

作者

陈越

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(<=1000),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积

其中 编号 是每个人独有的一个4位数的编号; 和  分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0<=k<=5)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

输出样例:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000

并查集,要维护的东西比较多,有点繁琐

大致思想就是将每个人都看成一个点,读入时按照家庭读入,但是住房与面积只给第一个编号的人(因为互不相同)

全部读入后,再用并查集合并即可

#include <cstdio>
#include <algorithm>

using namespace std;

const double EPS=0.0001;

struct Node {
    int index,peo;
    double buil,area;

    bool operator < (const Node& a) const {
        return area-EPS>a.area||(abs(area-a.area)<EPS&&index<a.index);
    }
}que[10005];

struct Fam {
    int i,f,m,k[5],n,b,a;
}p[1005];

int n,pa,pb,tail;
int par[10005],mn[100005],peo[10005],buil[10005],area[10005];
bool vis[10005];

int getPar(int a) {
    if(par[a]!=a) {
        par[a]=getPar(par[a]);
    }
    return par[a];
}

void merg(int a,int b) {
    pa=getPar(a);
    pb=getPar(b);
    if(pa!=pb) {
        par[pb]=pa;
        mn[pa]=min(mn[pa],mn[pb]);
        peo[pa]+=peo[pb];
        buil[pa]+=buil[pb];
        area[pa]+=area[pb];
    }
}

int main() {
    while(1==scanf("%d",&n)) {
        for(int i=0;i<10000;++i) {
            par[i]=mn[i]=i;
            peo[i]=1;
            buil[i]=0;
            area[i]=0;
            vis[i]=true;
        }
        for(int i=0;i<n;++i) {
            scanf("%d%d%d%d",&p[i].i,&p[i].f,&p[i].m,&p[i].n);
            for(int j=0;j<p[i].n;++j) {
                scanf("%d",&p[i].k[j]);
            }
            scanf("%d%d",&buil[p[i].i],&area[p[i].i]);
        }
        for(int i=0;i<n;++i) {
            vis[p[i].i]=false;
            if(p[i].f!=-1) {
                merg(p[i].i,p[i].f);
                vis[p[i].f]=false;
            }
            if(p[i].m!=-1) {
                merg(p[i].i,p[i].m);
                vis[p[i].m]=false;
            }
            for(int j=0;j<p[i].n;++j) {
                if(p[i].k[j]!=-1) {
                    merg(p[i].i,p[i].k[j]);
                    vis[p[i].k[j]]=false;
                }
            }
        }
        tail=0;
        for(int i=0;i<10000;++i) {
            if(!vis[i]&&par[i]==i) {
                que[tail].index=mn[i];
                que[tail].peo=peo[i];
                que[tail].area=1.0*area[i]/peo[i];
                que[tail++].buil=1.0*buil[i]/peo[i];
            }
        }
        sort(que,que+tail);
        printf("%d\n",tail);
        for(int i=0;i<tail;++i) {
            printf("%04d %d %.3lf %.3lf\n",que[i].index,que[i].peo,que[i].buil,que[i].area);
        }
    }
    return 0;
}

L2-4. 最长对称子串 (Manacher

时间限制

100 ms

内存限制

65536 kB

代码长度限制

8000 B

判题程序

Standard

作者

陈越

对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定"Is PAT&TAP symmetric?",最长对称子串为"s PAT&TAP s",于是你应该输出11。

输入格式:

输入在一行中给出长度不超过1000的非空字符串。

输出格式:

在一行中输出最长对称子串的长度。

输入样例:

Is PAT&TAP symmetric?

输出样例:

11

直接粘最长回文字串的模版即可,用Manacher算法

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,i,p[2000005];
char str[1000005],s[2000005];

int Manacher(char *ori) {
    s[0]=1;//第一个字符不同,防止越界
    s[1]=2;
    char *t=s+2;
    while(*ori) {
        *(t++)=*(ori++);
        *(t++)=2;
    }
    *(t++)='\0';

    int mxl=0,index=0;
    p[0]=0;
    for(int i=2;s[i];++i) {
        p[i]=(p[index]+index>i?min(p[(index<<1)-i],p[index]+index-i):1);
        while(s[i-p[i]]==s[i+p[i]])
            ++p[i];
        if(p[index]+index<p[i]+i)
            index=i;
        if(mxl<p[index])
            mxl=p[index];
    }
    return mxl-1;
}

int main() {
    while(gets(str)) {
        printf("%d\n",Manacher(str));
    }
    return 0;
}

L3-1. 肿瘤诊断 (BFS)

时间限制

400 ms

内存限制

65536 kB

代码长度限制

8000 B

判题程序

Standard

作者

陈越

在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环。给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积。

输入格式:

输入第一行给出4个正整数:M、N、L、T,其中M和N是每张切片的尺寸(即每张切片是一个M×N的像素矩阵。最大分辨率是1286×128);L(<=60)是切片的张数;T是一个整数阈值(若疑似肿瘤的连通体体积小于T,则该小块忽略不计)。

最后给出L张切片。每张用一个由0和1组成的M×N的矩阵表示,其中1表示疑似肿瘤的像素,0表示正常像素。由于切片厚度可以认为是一个常数,于是我们只要数连通体中1的个数就可以得到体积了。麻烦的是,可能存在多个肿瘤,这时我们只统计那些体积不小于T的。两个像素被认为是“连通的”,如果它们有一个共同的切面,如下图所示,所有6个红色的像素都与蓝色的像素连通。

Figure 1

输出格式:

在一行中输出肿瘤的总体积。

输入样例:

3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0

输出样例:

26

简单的连通块搜索,只是多了一维而已

#include <cstdio>

using namespace std;

const int di[]={-1,0,0,0,0,1};
const int dj[]={0,-1,0,1,0,0};
const int dk[]={0,0,1,0,-1,0};

struct Node {
    int i,j,k;
}que[61*1286*129],cur;

int m,n,l,t,ans,head,tail;
int num[61][1286][129];
bool vis[61][1287][129];

inline bool isInside(int i,int j,int k) {
    return 0<=i&&i<l&&0<=j&&j<n&&0<=k&&k<m;
}

int bfs(int stai,int staj,int stak) {
    head=tail=0;
    que[tail].i=stai;
    que[tail].j=staj;
    que[tail++].k=stak;
    vis[stai][staj][stak]=true;

    int res=1,ii,jj,kk;
    while(head!=tail) {
        cur=que[head++];
        for(int i=0;i<6;++i) {
            ii=cur.i+di[i];
            jj=cur.j+dj[i];
            kk=cur.k+dk[i];
            if(isInside(ii,jj,kk)&&!vis[ii][jj][kk]&&num[ii][jj][kk]==1) {
                ++res;
                vis[ii][jj][kk]=true;
                que[tail].i=ii;
                que[tail].j=jj;
                que[tail++].k=kk;
            }
        }
    }
    return res>=t?res:0;
}

int main() {
    while(4==scanf("%d%d%d%d",&n,&m,&l,&t)) {
        for(int i=0;i<l;++i) {
            for(int j=0;j<n;++j) {
                for(int k=0;k<m;++k) {
                    scanf("%d",&num[i][j][k]);
                    vis[i][j][k]=false;
                }
            }
        }
        ans=0;
        for(int i=0;i<l;++i) {
            for(int j=0;j<n;++j) {
                for(int k=0;k<m;++k) {
                    if(!vis[i][j][k]&&num[i][j][k]==1) {
                        ans+=bfs(i,j,k);
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-09-29 02:38:23

2016年 团体程序设计天梯赛 - 模拟赛的相关文章

2016年团体程序设计天梯赛-模拟赛

L2-4. 最长对称子串 注意连续子串 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <stack> #include <string> #include <queue> #include <vecto

PAT 团体程序设计天梯赛-练习集L1-011. A-B

本题要求你计算A-B.不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A-B. 输入格式: 输入在2行中先后给出字符串A和B.两字符串的长度都不超过104,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束. 输出格式: 在一行中打印出A-B的结果字符串. 输入样例: I love GPLT! It's a fun game! aeiou 输出样例: I lv GPLT! It's fn gm! 1 #inclu

PAT 团体程序设计天梯赛-练习集 L1-015. 跟奥巴马一起画方块

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形.现在你也跟他一起画吧! 输入格式: 输入在一行中给出正方形边长N(3<=N<=21)和组成正方形边的某种字符C,间隔一个空格. 输出格式: 输出由给定字符C画出的正方形.但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的50%(四舍五入取整). 输入样例

PAT 团体程序设计天梯赛-练习集 L1-007. 念数字

输入一个整数,输出每个数字对应的拼音.当整数为负数时,先输出“fu”字.十个数字对应的拼音如下: 0: ling 1: yi 2: er 3: san 4: si 5: wu 6: liu 7: qi 8: ba 9: jiu 输入格式: 输入在一行中给出一个整数,如: 1234 . 提示:整数包括负数.零和正数. 输出格式: 在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格.如 yi er san si. 输入样例: -600 输出样例: fu liu ling

PAT 团体程序设计天梯赛-练习集 L1-005. 考试座位号

每个PAT考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位.正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试座位就座.但有些考生迟到了,试机已经结束,他们只能拿着领到的试机座位号码求助于你,从后台查出他们的考试座位号码. 输入格式: 输入第一行给出一个正整数N(<=1000),随后N行,每行给出一个考生的信息:“准考证号 试机座位号 考试座位号”.其中准考证号由14位数字组成,座位从1到N编号.输入保证每个

PAT 团体程序设计天梯赛-练习集 L1-016. 查验身份证

一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}:然后将计算的和对11取模得到值Z:最后按照以下关系对应Z值与校验码M的值: Z:0 1 2 3 4 5 6 7 8 9 10M:1 0 X 9 8 7 6 5 4 3 2 现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码. 输入格式: 输入第一行给出正整数N(<= 100

PAT 团体程序设计天梯赛-练习集 L1-017. 到底有多二

一个整数“犯二的程度”定义为该数字中包含2的个数与其位数的比值.如果这个数是负数,则程度增加0.5倍:如果还是个偶数,则再增加1倍.例如数字“-13142223336”是个11位数,其中有3个2,并且是负数,也是偶数,则它的犯二程度计算为:3/11*1.5*2*100%,约为81.82%.本题就请你计算一个给定整数到底有多二. 输入格式: 输入第一行给出一个不超过50位的整数N. 输出格式: 在一行中输出N犯二的程度,保留小数点后两位. 输入样例: -13142223336 输出样例: 81.8

PTA|团体程序设计天梯赛-练习题目题解锦集(C/C++)(持续更新中……)

PTA|团体程序设计天梯赛-练习题目题解锦集(持续更新中) 实现语言:C/C++:      欢迎各位看官交流讨论.指导题解错误:或者分享更快的方法!! 题目链接:https://pintia.cn/problem-sets/994805046380707840/problems 目录 (点击对应题目即可进入相应题解--小声BB--) L1-001 Hello World (5 分) L1-002 打印沙漏 (20 分) L1-003 个位数统计 (15 分) L1-004 计算摄氏温度 (5

【题解】PAT团体程序设计天梯赛 - 模拟赛

由于本人愚笨,最后一题实在无力AC,于是只有前14题的题解Orz 总的来说,这次模拟赛的题目不算难,前14题基本上一眼就有思路,但是某些题写起来确实不太容易,编码复杂度有点高~ L1-1 N个数求和 设计一个分数类,重载加法运算符,注意要约分,用欧几里得算法求个最大公约数即可. 1 #include <cstdio> 2 3 long long abs(long long x) 4 { 5 return x < 0 ? -x : x; 6 } 7 8 long long gcd(long