upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路)

本文主要是介绍upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题 A: 13号星期几

题目描述
请编程统计:从1900年1月1日(当天是星期一)开始经过的n年当中,每个月的13号这一天是星期一、星期二、星期三、……、星期日的次数分别是多少?
输入
共一行,一个整数n (1≤n≤400)。
输出
仅一行, 有7个整数(依次是星期一、星期二、星期三、……、星期日的次数),各数间以空格相隔,行尾不能有多余的空格。
样例输入 Copy
1
样例输出 Copy
1 3 1 2 2 2 1

思路:
定义一个x,让他从1号开始循环,如果加一大于当前月份的值,就结束当前月份的循环,循环的同时判断对7取余的值,相应的余数开一个数组然后++即可

int n,x,t;
int a[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int vis[10];//记录周一到周天是13号的次数
int judge(int y)
{if((y%4 == 0 && y%100 != 0) || (y%400 == 0))return 1;else    return 0;
}int main()
{cin >> n;for(int i=1900;i<1900+n;i++){if(judge(i))    a[2]++;else    a[2] = 28;for(int j=1;j<=12;j++)//月份{x = 0;while(1){if(x+1 > a[j])   break;x++;t = (t+1)%8;if(t == 0)  t = 1;if(x == 13) vis[t]++;}}}for(int i=1;i<=7;i++)printf("%d ",vis[i]);printf("\n");return 0;
}

问题 B: 高兴的小明

题目描述
今天,小明很高兴,因为国庆放假了,又恰逢是自己的生日。为了庆祝节日,小明与邻居的小伙伴共n个人相约一起放花炮。他们先同时放响了第一个花炮,随后n个人分别以A1、A2、A3、……An秒的间隔继续放花炮,到最后每人都放了b个花炮(包括第一个)。问:总共可听到多少声花炮响?
输入
共三行,第一行仅一个整数n(n<=10),第二行是A1、A2、A3、……An共n个整数(每个数<=100,各数间以空格相隔),第三行只有一个整数b(b<=100)。
输出
仅一行,一个整数(听到的花炮响声数),行尾不能有多余的空格。
样例输入 Copy
3
1 2 3
4
样例输出 Copy
7

思路:
首先第一个花炮是同时放的,所以只能听到一次声响,即从ans = 1开始,之后观察数据发现,每个人放花炮听到声响其实就是一个等差数列,给出的间隔就是公差,同时在同一时间放出的花炮只能听见一次声响,问题就解决了
我一开始想用数组直接记录下放花炮的时间,最后发现还需要去重,于是我就想到了另外一种办法,可以直接让放花炮的时间做数组的下标,如果能听到就标记为1,这样就不容易出错了

int n,b,ans,cnt;
int a[15],c[10005];
int main()
{cin >> n;for(int i=1;i<=n;i++)    cin >> a[i];cin >> b;for(int i=1;i<=n;i++){for(int j=1;j<=b-1;j++){c[j*a[i]] = 1;}}ans = 1;for(int i=1;i<=10000;i++){if(c[i] == 1)   ans++;}cout << ans << endl;return 0;
}

问题 C: 摘彩球

题目描述
今年是国庆60周年,学校少先队大队部举行了庆祝活动,其中有一项活动是摘彩球。大队辅导员在学校礼堂里高低不一地挂了N个彩球,请M位少先队员到礼堂里摘彩球。辅导员说:你们每人最多可以摘两个彩球,而且只许站着伸手摘,不允许借助其它工具,摘下的彩球归大家共有。由于各少先队员的身高参差不齐,怎样才能使他们摘的彩球总数最多呢?请你计算少先队员们最多能摘到多少个彩球?
输入
第一行有二个整数N 和M(N<=100,M<=20),两数间用空格隔开。
第二行有 N个整数(各数间以空格相隔),分别表示每个彩球的高度。
第三行有M个整数(各数间以空格相隔),分别表示每个少先队员伸手能达到的高度。
输出
仅一行,有一个整数,表示最多能摘到的彩球数,行尾不能有多余的空格。
样例输入 Copy
10 4
110 100 150 90 100 135 160 88 130 140
120 100 110 80
样例输出 Copy
5

思路:
这个题我先排序然后去掉了根本就够不到的彩球,然后循环比较大小,一旦彩球可以被摘下来,就把彩球的高度变为1,循环过程中不断判断ans % 2,如果为0,结束本次循环

int n,m,x,ans,cnt;
int a[105],b[25];
bool cmp(int x,int y)
{return x > y;
}int main()
{cin >> n >> m;for(int i=1;i<=n;i++)    cin >> a[i];for(int i=1;i<=m;i++)    cin >> b[i];sort(a+1,a+1+n,cmp);//降序 sort(b+1,b+1+m,cmp);for(int i=1;i<=n;i++){if(b[1] < a[i])  a[i] = 0;}//去掉根本够不到的 for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if((b[i] >= a[j]) && (a[j] != 0)){ans++;a[j] = 0;if(ans%2 == 0)  break;}}}cout << ans << endl;return 0;
}

问题 D: 莱布尼茨三角形

题目描述
世界上著名的莱布尼茨三角形如图所示,请编程输出图中排在第n行从左边数第m个位置上的数。
在这里插入图片描述
输入
共一行,有二个整数N 和M(N<=15),两数间用空格隔开。
输出
共一行,有二个整数,两数间用“/”隔开,表示所求的分数,行尾没有多余的空格。
样例输入 Copy
7 3
样例输出 Copy
1/105

思路:
这个题我的思路是先建立起图示的三角形,然后查找就可以了,观察这个三角形,利用我高中对数组求和留下的深刻印象,我一眼就发现了,从第三列开始,每一列从第二个数开始等于它上一行前一列的数减去它前一个数,即a[i][j] = a[i-1][j-1] - a[i][j-1],同时这个三角形又是对称的,即a[i][j] = a[i][i-j+1],我们知道分子一定是1,所以每次只需要计算分母就可以了

int a[20][20];
int n,m,ans;
int jianfa(int a,int b)//求分母 
{int x,y,z;z = gcd(a,b);y = a*b/z;x = 1*(y/a)-1*(y/b);z = gcd(x,y);y = y/z;return y;
}int main()
{cin >> n >> m;for(int i=1;i<=15;i++){a[i][1] = a[i][i] = i; }for(int i=3;i<=15;i++){for(int j=2;j<=(i-1)/2+1;j++)//上取整 {a[i][j] = a[i][i-j+1] = jianfa(a[i-1][j-1],a[i][j-1]);}}for(int i=1;i<=15;i++){for(int j=1;j<=15;j++){ans = a[n][m];}}printf("1/%d",ans);return 0;
}

问题 E: 黑匣子

题目描述
Black Box是一种原始的数据库。它可以存储一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的,而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进Black Box;
GET:i加1,然后输出Black Box中第i小的数。
记住:第i小的数,就是Black Box里的数按从小到大的顺序排序后的第i个元素。
例如: 我们来演示一下一个有11个命令的命令串。(如下图所示)
序号 操作 i 数据库 输出
1 ADD(3) 0 3
2 GET 13 3
3 ADD(1) 11, 3
4 GET 21,3 3
5 ADD(-4) 2 -4,1, 3
6 ADD(2) 2-4,1,2,3
7 ADD(8) 2-4,1,2,3,8
8 ADD(-1000)2-1000,-4,1,2,3,8
9 GET 3 -1000,-4,1,2,3,81
10 GET 4 -1000,-4,1,2,3,8 2
11 ADD(2) 4-1000,-4,1,2,2,3,8

现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多有200000个。

现在用两个整数数组来表示命令串:
1、A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对不超过2000000000的整数,M≤200000。例如上面的例子就是
A=(3,1,-4,2,8,-1000,2)。
2、u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现了一个GET命令。例如上面的例子中的u=(1,2,6,6)。
输入数据不用判错。

输入
第一行,两个整数,M,N。
第二行,M个整数,表示A(1) …A(M)。
第三行,N个整数,表示u(1)…u(N)。
输出
输出Black Box根据命令串所得出的输出串,一个数字一行。
样例输入 Copy
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
样例输出 Copy
3
3
1
2
提示
对于30%的数据,M≤10000;
对于50%的数据,M≤100000
对于100%的数据,M≤200000

思路:
这个题的题意我是读了好几遍才明白的,它是说有一个堆,一开始是个空堆,同时有一个变量s = 0,现在有两种操作,ADD和GET,ADD表示元素要入队,当当前第u[i]个数入队时,GET一下,s++,并且输出当前第s小的数。由于要不停的输出第s小的数,我想了很久,发现用数组一遍遍的查找太麻烦,于是想到了今天看了很久的数据结构,发现这个规律貌似可以用优先队列来解决
用两个优先队列分别维护a[i]和u[i],将a[i]存放在大根堆中,如果大根堆的元素数量大于s时,就把大根堆的队顶元素放进小根堆,一旦满足GET的条件,只需要输出当前小根堆的队顶元素即可

int a[maxn],b[maxn],n,m;
int main()
{cin >> n >> m;for(int i=1; i<=n; i++)	scanf("%d",&a[i]);for(int i=1; i<=m; i++)	scanf("%d",&b[i]);int s = 0,k = 1;for(int i=1; i<=n; i++){q2.push(a[i]);//入队 if(q2.size() > s) q1.push(q2.top()),q2.pop();//q2的队顶元素放进q1while(b[k] == i)//遇到这个操作,相对应的迭代器s++ //输出第s小,放进q1的自动按小到大排序,每次输出队顶元素即可 {printf("%d\n",q1.top());k++;//控制循环 s++;q2.push(q1.top());//放回q2 q1.pop(); }}return 0;
}

问题 F: 选地址

题目描述
小X有很多朋友、、分布在N个城市。。
这N个城市之间,有些有直接的道路,有些是间接联通的(保证任何两个城市都可以相互到达。。)
但是、经过每条道路都是有代价的、、
于是。。
小X希望你来帮他找出一个城市,使得他的所有朋友到这个城市的代价最小。
输入
输入共2N+1行,
其中第一行为一个整数N、
第2~N+1行
每行有N个整数、表示两个城市间的代价、(0表示不直接连通)
第n+2~2
N+1行
每行一个整数。表示每个城市中小X的朋友数。
输出
输出有两行。
第一行为你选中的城市
第二行为最小需要的代价。
样例输入 Copy
5
0 1 2 0 0
1 0 0 0 20
2 0 0 10 0
0 0 10 0 1
0 20 0 1 0
2
3
4
5
6
样例输出 Copy
4
109
提示
对于100%的数据,n<=200,输出保证不超过long long int

思路:
这个题一开始做的时候,明白题意但是不会啊,基本无从下手,后来得到dalao指点,去学习了弗洛伊德最短路。这个题就是求出每两个城市之间的最短路径,然后去乘以相应的朋友数量,取最小值

int n;
ll ans,tmp,id;
ll dis[1000][1000],num[1000];
// i -> j 的最短路径的长度 
int main()
{int n;	scanf("%d",&n);memset(dis,0x3f3f3f3f,sizeof dis);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){ll x;	scanf("%lld",&x);if(x)//不为0时说明直接连通{dis[i][j] = x;}}}for(int i=1;i<=n;i++)	scanf("%lld",&num[i]);for(int k=1;k<=n;k++)//弗洛伊德最短路 O(n^3){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(dis[i][k] + dis[k][j] < dis[i][j]){dis[i][j] = dis[i][k] + dis[k][j];//求出两个城市之间的最短路径}}}}ans = 1e18 , id = -1;//赋ans一个很大的值for(int i=1;i<=n;i++){tmp = 0;for(int j=1;j<=n;j++){if(i != j)tmp += num[j] * dis[i][j];}if(ans > tmp){ans = tmp;id = i;}}printf("%lld\n%lld\n",id,ans);return 0;
}

这篇关于upc 个人训练赛第四场:黑匣子+选地址(优先队列+弗洛伊德最短路)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/282732

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

Python中使用正则表达式精准匹配IP地址的案例

《Python中使用正则表达式精准匹配IP地址的案例》Python的正则表达式(re模块)是完成这个任务的利器,但你知道怎么写才能准确匹配各种合法的IP地址吗,今天我们就来详细探讨这个问题,感兴趣的朋... 目录为什么需要IP正则表达式?IP地址的基本结构基础正则表达式写法精确匹配0-255的数字验证IP地

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

Linux配置IP地址的三种实现方式

《Linux配置IP地址的三种实现方式》:本文主要介绍Linux配置IP地址的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录环境RedHat9第一种安装 直接配置网卡文件第二种方式 nmcli(Networkmanager command-line

Linux虚拟机不显示IP地址的解决方法(亲测有效)

《Linux虚拟机不显示IP地址的解决方法(亲测有效)》本文主要介绍了通过VMware新装的Linux系统没有IP地址的解决方法,主要步骤包括:关闭虚拟机、打开VM虚拟网络编辑器、还原VMnet8或修... 目录前言步骤0.问题情况1.关闭虚拟机2.China编程打开VM虚拟网络编辑器3.1 方法一:点击还原VM

使用DeepSeek搭建个人知识库(在笔记本电脑上)

《使用DeepSeek搭建个人知识库(在笔记本电脑上)》本文介绍了如何在笔记本电脑上使用DeepSeek和开源工具搭建个人知识库,通过安装DeepSeek和RAGFlow,并使用CherryStudi... 目录部署环境软件清单安装DeepSeek安装Cherry Studio安装RAGFlow设置知识库总

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring