2018 CCCC 团队天梯赛(补题)(二)中间7题

7-16 矩阵A乘以B (15 分)

给定两个矩阵A和B,要求你计算它们的乘积矩阵AB。需要注意的是,只有规模匹配的矩阵才可以相乘。即若A有R​a​​行、C​a​​列,B有R​b​​行、C​b​​列,则只有C​a​​与R​b​​相等时,两个矩阵才能相乘。

输入格式:

输入先后给出两个矩阵A和B。对于每个矩阵,首先在一行中给出其行数R和列数C,随后R行,每行给出C个整数,以1个空格分隔,且行首尾没有多余的空格。输入保证两个矩阵的R和C都是正数,并且所有整数的绝对值不超过100。

输出格式:

若输入的两个矩阵的规模是匹配的,则按照输入的格式输出乘积矩阵AB,否则输出Error: Ca != Rb,其中Ca是A的列数,Rb是B的行数。

输入样例1:

2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

输出样例1:

2 4
20 22 24 16
53 58 63 28

输入样例2:

3 2
38 26
43 -5
0 17
3 2
-11 57
99 68
81 72

输出样例2:

Error: 2 != 3

这个题目简单的矩阵相乘...结果当时打的时候看到了后面的两个题好像写过,结果卡在后面了运行超时了....到最后简单的题目反而没有时间来写了,引以为戒吧,下面是代码:

#include<bits/stdc++.h>
using namespace std;
int a[110][110],b[110][110],temp[110][110];
int main()
{
	int ra,ca,rb,cb;
	while(~scanf("%d%d",&ra,&ca))
	{
		for(int i=1;i<=ra;i++)
		{
			for(int j=1;j<=ca;j++)
			{
				scanf("%d",&a[i][j]);
			}
		}
		scanf("%d%d",&rb,&cb);
		for(int i=1;i<=rb;i++)
		{
			for(int j=1;j<=cb;j++)
			{
				scanf("%d",&b[i][j]);
			}
		}
		if(ca!=rb)
		{
			printf("Error: %d != %d\n",ca,rb);
			continue;
		}
		printf("%d %d\n",ra,cb);
		for(int i=1;i<=ra;i++)
		{
			for(int j=1;j<=cb;j++)
			{
				int sum=0;
				for(int k=1;k<=rb;k++)
				{
					sum+=a[i][k]*b[k][j];
				}
				printf("%d",sum);
				if(j<=cb-1)
				printf(" ");
			}
			printf("\n"); 
		}
	}
	return 0;
} 

L1-8 猜数字 (20 分)

一群人坐在一起,每人猜一个 100 以内的数,谁的数字最接近大家平均数的一半就赢。本题就要求你找出其中的赢家。

输入格式:

输入在第一行给出一个正整数N(≤10​4​​)。随后 N 行,每行给出一个玩家的名字(由不超过8个英文字母组成的字符串)和其猜的正整数(≤ 100)。

输出格式:

在一行中顺序输出:大家平均数的一半(只输出整数部分)、赢家的名字,其间以空格分隔。题目保证赢家是唯一的。

输入样例:

7
Bob 35
Amy 28
James 98
Alice 11
Jack 45
Smith 33
Chris 62

输出样例:

22 Amy

暴力大fa好!!!,世界上没有什么事暴力解决不了的,如果有,那就是因为不够暴力!!! 

#include<bits/stdc++.h>
using namespace std;
const int infa=1e9+7;
int main()
{
    int n,sum,a[100010],ave,minn,ans;
    char ch[11010][110];
    while(~scanf("%d",&n))
    {
        sum=0,minn=infa;
        memset(a,0,sizeof(a));
        memset(ch,0,sizeof(ch));
        for(int i=1;i<=n;i++)
        {
            scanf("%s%d",ch[i],&a[i]);
        }
        for(int i=1;i<=n;i++)
        {
            sum+=a[i];
        }
        ave=(sum/n)/2;
        for(int i=1;i<=n;i++)
        {
            minn=min(minn,abs(a[i]-ave));
        }
        for(int i=1;i<=n;i++)
        {
            if(abs(a[i]-ave)==minn)
            {
                ans=i;
                break;
            }
        }
        printf("%d %s\n",ave,ch[ans]);
    }
    return 0;
}

 

L1-1 天梯赛座位分配 (20 分)

天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员…… 以此类推。如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。

输入格式:

输入在一行中给出参赛的高校数 N (不超过100的正整数);第二行给出 N 个不超过10的正整数,其中第 i 个数对应第 i 所高校的参赛队伍数,数字间以空格分隔。

输出格式:

从第 1 所高校的第 1 支队伍开始,顺次输出队员的座位号。每队占一行,座位号间以 1 个空格分隔,行首尾不得有多余空格。另外,每所高校的第一行按“#X”输出该校的编号X,从 1 开始。

输入样例:

3
3 4 2

输出样例:

#1
1 4 7 10 13 16 19 22 25 28
31 34 37 40 43 46 49 52 55 58
61 63 65 67 69 71 73 75 77 79
#2
2 5 8 11 14 17 20 23 26 29
32 35 38 41 44 47 50 53 56 59
62 64 66 68 70 72 74 76 78 80
82 84 86 88 90 92 94 96 98 100
#3
3 6 9 12 15 18 21 24 27 30
33 36 39 42 45 48 51 54 57 60

这个题目我觉得是中间七题里面比较难的一道题了,当时看了题目就直接跳过去了,后来想想这样的题目老是不做好像不太好,干脆回来补一下算了...

这个题目我们可以用三维数组来做,f[i][j][k]记载的队员的编号,然后i j k 分别表示的是 i 个学校, j 个队,当前状态下这个队里有k 个人,然后就是一个三重循环来做,记得用一个temp中间变量来存下来上一次是哪个学校的,如果是一个学校的话那么就+2,不是的话相邻就可以了,下面是我的代码:

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
int n,maxx,last,beg,s[maxn],f[maxn][10][10];//s[maxn]记载的是每个学校队里的人数,f[maxn][10][10]记载的是题解里面的状态;
int main()
{
	while(~scanf("%d",&n))
	{
		maxx=0,beg=0;//maxx,beg,分别记载一共要多少次和初始化开始的位置; 
		for(int i=0;i<n;i++)
		{
			scanf("%d",&s[i]);
			maxx=max(maxx,s[i]);
		}
		//last记载的是上一个学校 
		last=-1;
		for(int j=0;j<maxx;j++)//第几个队 
		{
			for(int k=0;k<10;k++)//第几个队员 
			{
				for(int i=0;i<n;i++)//第几个学校 
				{
					if(s[i]<=j)
					continue;//最开始的几个地方可以去省掉,如果队数比学校数还要多,那就直接跳过; 
					if(last==i)//如果是一个学校的,那就直接隔一个跳 
					beg+=2;
					else
					beg+=1;//否则就隔一个; 
					f[i][j][k]=beg;//记录这个状态下,队员的编号; 
					last=i;//更新上一个学校的状态值; 
				}
			}
		}
		//输出;
		for(int i=0;i<n;i++)
		{
			printf("#%d\n",i);
			for(int j=0;j<s[i];j++)
			{
				for(int k=0;k<10;k++)
				{
					if(k!=1)
					{
						printf(" ");
					}
					printf("%d",f[i][j][k]);
				}
				printf("\n");
			} 
		} 
	}
	return 0;
} 

 

7-14 整除光棍 (20 分)

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:

输入在一行中给出一个不以5结尾的正奇数x(<1000)。

输出格式:

在一行中输出相应的最小的sn,其间以1个空格分隔。

输入样例:

31

输出样例:

3584229390681 15

这个题目我刚开始看了一下准备用高精度写的,后来觉得范围实在太大,而且如果用高精度的话,后面数值的比较还要一位一位的来,所以我觉得很麻烦,所以就没有理他,直接跳到其他题目的,后来看了看别人的想法,发现自己想的太复杂了...(当然是因为菜qwq)

代码如下:

 

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,x,temp,ans,cnt;
	while(~scanf("%d",&n))
	{
		cnt=1;//计算一共有多少位 
		temp=n;//中间变量存储n,方便下一步的计算; 
		x=1;//光棍数的小帮手。。。 
		while(temp/10)
		{
			temp/=10;
			x+=pow(10,cnt);
			cnt++;
		}
		if(n==x)//最开始这种一上来就相等的情况也完全没有考虑到,还是做题做的太少了,考虑的不厚周到 
		{
			printf("1 %d\n",cnt);
			continue;
		}
		x+=pow(10,cnt);//和它自己等位数的不行,试一试下一个,即多一位的那个;
		while(x%n)//如果下一位也不行的话 
		{
			printf("%d",x/n);//挨个尝试,题目好像可以保证一定找得到,所以就可以直接穷举, 
			x=(x%n)*10+1;//相当于是高精度除以低精度的除法运算,但是,这个地方因为是光棍数,注意以前是除下来多了一个0,现在是1; 
			cnt++;//统计位数 
		}
		printf("%d %d\n",x/n,cnt+1); //输出,注意位数加一 
		 
	}
	return 0;
} 

L2-1 分而治之 (25 分)

分而治之,各个击破是兵家常用的策略之一。在战争中,我们希望首先攻下敌方的部分城市,使其剩余的城市变成孤立无援,然后再分头各个击破。为此参谋部提供了若干打击方案。本题就请你编写程序,判断每个方案的可行性。

输入格式:

输入在第一行给出两个正整数 N 和 M(均不超过10 000),分别为敌方城市个数(于是默认城市从 1 到 N 编号)和连接两城市的通路条数。随后 M 行,每行给出一条通路所连接的两个城市的编号,其间以一个空格分隔。在城市信息之后给出参谋部的系列方案,即一个正整数 K (≤ 100)和随后的 K 行方案,每行按以下格式给出:

Np v[1] v[2] ... v[Np]

其中 Np 是该方案中计划攻下的城市数量,后面的系列 v[i] 是计划攻下的城市编号。

输出格式:

对每一套方案,如果可行就输出YES,否则输出NO

输入样例:

10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 10
2 4
5
4 10 3 8 4
6 6 1 7 5 4 9
3 1 8 4
2 2 8
7 9 8 7 6 5 4 2

输出样例:

NO
YES
YES
NO
NO

刚开始的想法,这个题目就是用一个二维数组来存这个图,到最后遍历一遍就可以了,就是再标记一些啥的,最后用标记的结果来判断就可以了,不过做了过后老是爆数据和内存,后来突然发现应该用结构体就可以了(嘤嘤嘤)

不过这个题目只得了23分....不知道哪里被卡住了,不过我感觉我思路超级对的说,,,希望大佬帮我看看哪里的bug

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
struct a
{
    int x,y;//记录两个城市; 
}fuck[maxn];
int main()
{
    int m,n,ta,tb,k,you,tyou,flag,mark[maxn];
    struct a fuck[maxn];
    while(~scanf("%d%d",&n,&m))
    {
        memset(fuck,0,sizeof(fuck));
        for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&ta,&tb);
                fuck[i].x=ta;
                fuck[i].y=tb;
            }
            scanf("%d",&k);
            for(int i=1;i<=k;i++)
            {
                flag=1,memset(mark,0,sizeof(mark));//标志变量和标记数组,记得每一次都要初始化,恢复状态; 
                scanf("%d",&you);
                for(int j=1;j<=you;j++)
                {
                    scanf("%d",&tyou);
                    mark[tyou]=1;//被破了,记为1; 
                }
                for(int i=1;i<=n;i++)//每一条边来遍历 
                {
                  if(mark[fuck[i].x]==0&&mark[fuck[i].y]==0)//如果这个边两边都没有破,,证明根本就没有联通,那还打个锤子,那不行,标记,跳了 
                  {
                    flag=0;
                    break;
                  }
                }
                if(flag==0)
                  printf("NO\n");
                else
                  printf("YES\n");
            }
    }
    return 0;
}

 

 

 

L2-2 小字辈 (25 分)

本题给定一个庞大家族的家谱,要请你给出最小一辈的名单。

输入格式:

输入在第一行给出家族人口总数 N(不超过 100 000 的正整数) —— 简单起见,我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号,其中第 i 个编号对应第 i 位成员的父/母。家谱中辈分最高的老祖宗对应的父/母编号为 -1。一行中的数字间以空格分隔。

输出格式:

首先输出最小的辈分(老祖宗的辈分为 1,以下逐级递增)。然后在第二行按递增顺序输出辈分最小的成员的编号。编号间以一个空格分隔,行首尾不得有多余空格。

输入样例:

9
2 6 5 5 -1 5 6 4 7

输出样例:

4
1 9

这个题目看题意的话我首先想到了并查集,不过后来发现使用dfs回溯就可以写出来,这个题我们可以把它看成是一颗树,也就是从树从上到下依次遍历寻找,因为每个节点有可能有多个子代,所以我们可以用vector来进行贮存,我还看见有用优先队列来的,也很好,不过菜鸡的我对于优先队列掌握的不是很好,所以qwq....

上代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int dep[maxn],beg,temp,k,flag,n;
vector<int> t[maxn];
void dfs(int biao,int depth)//从biao这个节点开始搜,深度为depth; 
{
	dep[biao]=depth;//记录这个点的深度; 
	beg=max(beg,depth);//记录最大值也就是最深和最晚辈; 
	for(int i=0;i<t[biao].size();i++)//这个里面的儿子都来一遍 
	{
		dfs(t[biao][i],depth+1);//看看有没有更深的 
	}
 } 
int main()
{
	while(~scanf("%d",&n))
	{
		beg=1,temp=-1,flag=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&k);
			t[k].push_back(i);//这个人的儿子入进去; 
			if(k==-1) //找到老祖宗,也就是最高的点开始往下遍历; 
			temp=i;
		}
		dep[temp]=1;//最高一辈,从一开始; 
		dfs(temp,1);
		printf("%d\n",beg);//记录最后的深度并输出; 
		for(int i=1;i<=n;i++)
		{
			if(flag==0&&beg==dep[i])//控制空格的输出技巧而已, 
			{
				printf("%d",i);
				flag=1;
			}
			else if(beg==dep[i])//当这个深度对应着是最后的那个深度时,输出。 
			{
				printf(" %d",i);
			}
		}
		printf("\n");
	}
	return 0;
} 

 

L2-3 名人堂与代金券 (25 分)

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。

输入格式:

输入在第一行给出 3 个整数,分别是 N(不超过 10 000 的正整数,为学生总数)、G(在 (60,100) 区间内的整数,为题面中描述的代金券等级分界线)、K(不超过 100 且不超过 N 的正整数,为进入名人堂的最低名次)。接下来 N 行,每行给出一位学生的账号(长度不超过15位、不带空格的字符串)和总评成绩(区间 [0, 100] 内的整数),其间以空格分隔。题目保证没有重复的账号。

输出格式:

首先在一行中输出发出的 PAT 代金券的总面值。然后按总评成绩非升序输出进入名人堂的学生的名次、账号和成绩,其间以 1 个空格分隔。需要注意的是:成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出。

输入样例:

10 80 5
cy@zju.edu.cn 78
cy@pat-edu.com 87
1001@qq.com 65
uh-oh@163.com 96
test@126.com 39
anyone@qq.com 87
zoe@mit.edu 80
jack@ucla.edu 88
bob@cmu.edu 80
ken@163.com 70

输出样例:

360
1 uh-oh@163.com 96
2 jack@ucla.edu 88
3 anyone@qq.com 87
3 cy@pat-edu.com 87
5 bob@cmu.edu 80
5 zoe@mit.edu 80

因为时间有点晚,这个题的代码就不上了,简单说一下思路,输入了过后注意利用STL库里面的sort函数,在最后加上一个

bool cmp(struct a ta,struct a tb)
{
    if(ta.score==tb.score)
    {
        return ta.s<tb.s;
    }
    else if(ta.score!=tb.score)
        return ta.score>tb.score;
}

这样的东西加入sort函数帮忙排序就行了,

唯一注意的时最后的输出有坑,有并列的,处理一下就好了,这里引用了我看到的比较好的写法

 a[0].id = 1;
    for(int i = 1;i < n;i ++)
    {
        if(a[i].df == a[i - 1].df) a[i].id = a[i - 1].id;//如果分数相等,就把id都相等
        else a[i].id = i+1;//否则+1;
    }
    cout << ans << endl;
    for(int i = 0; a[i].id <=k;i ++)//循环的中间部分,看最后的id到了没有,
    {
        if(i >= n) return 0;//比总数还多当然不行
        else
        cout << a[i].id << " " << a[i].zh << " " << a[i].df << endl;//其它情况直接输出
    }

补题就到这里了(菜鸡还是需要努力啊,补题的时候看了好多大佬的题解,真的超级棒啊!)加油!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值