通过这次天梯模拟赛,意识到了自己的编程程度竟是那么的不堪一击。在大神的博客中看到此文,特转载记录,供你我共勉。
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;
}