2021年广东工业大学第十五届文远知行杯程序设计竞赛(同步赛) 部分题解

 


先声明,这场我爆0了一题都没做出来。

 

B题

链接:https://ac.nowcoder.com/acm/contest/13504/B
来源:牛客网
 

题目描述

母牛哥在电脑面前坐久了,想站起来看看窗外的小山坡,于是就想出了这个问题:

给定一个大小为n的数组a,序号从1开始,

计算:

max{ R - L | 1 <= L <= R <= n, a[L] == a[R], 对于所有i (L <= i <= R), 满足a[i] >= a[L] }.

也就是找到两个坐标,这两个坐标的值相等,并且他们之间的值都大于等于这两个坐标上的值.

这两个坐标相减最大能是多少.

 

输入描述:

第一行一个整数n,第二行n个整数

输出描述:

 

输出题目所求的值

示例1

输入

5
1 2 3 2 1

输出

4

说明

当L=1,R=5时,满足题目条件的最优解,答案为R-L=5-1=4

备注:

 

数据范围:

1<=n<=1e6

0<=a[i]<=1e9

 

题解:

栈。

建一个栈,当出现比栈顶小的数时,一路往回退,退到小于或等于它的数。

因为大于它的数,绝对不会在后面找相同的数组成区间,已经不满足条件了,所以可以直接去掉。

往回找,找到小于或等于它的数。

如果小于它,则表示它仍可以被纳入一个区间里。

如果等于它,则代表已经可以组成一个两边相等中间全比它大的区间了,就计算。

但是要注意像 1 2 2 2 1 3 3 1 这样的数据,当你第二个1往回找到第一个1的时候,不要将第二个1入栈,因为第三个1可以和第一个1组成一个更长的区间,这一点需要注意。

 

代码:

#include<iostream>
#include<stack>
using namespace std;

int n,a[1000006],ans;
stack<int> s;
int main()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	s.push(1);
	for(int i=2;i<=n;i++)
	{
		while(!s.empty() && a[s.top()]>a[i])
		  s.pop();
        bool f=false;
		if(!s.empty() && a[s.top()]==a[i])
        {
		  ans=max(ans,i-s.top());
            f=true;
        }
        if(!f)
            s.push(i); 
	 } 
    cout<<ans;
	return 0;
}

 

 

C题

链接:https://ac.nowcoder.com/acm/contest/13504/C
来源:牛客网
 

题目描述

母牛哥有一桶油漆,把它用完可以给n平方米的墙涂上颜色.

母牛哥想要在墙上涂5个正方形(这些正方形的边长都是整数,单位是米),并且刚好把油漆用完.

母牛哥能做到吗?

 

输入描述:

 

第一行一个数字t(<=1000),表示测试样例数量

接下来t行,每行一个数字n(0<=n<=1000000),表示母牛哥的油漆可以涂多少平方米.

输出描述:

 

输出t行,对于每个输入.

如果母牛哥能够做到,就输出YES.

否则输出NO.

示例1

输入

2
4
55

输出

NO
YES

说明

4显然不能分解成5个正平方数,所以这桶油漆不能涂5个正方形.

55可以涂5个正方形,他们面积分别是1 4 9 16 25.

 

 

题解:

其实,只是为了做题的话,先打个表,暴力算算那些不合适,然后直接特判即可。

具体证明为什么除那些数外都可以由5个平方数组成大家有兴趣可以上网查阅资料。

#include<iostream>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int a;
		cin>>a;
		if(a<5 || a==6 || a==7 || a==9 || a==10 || a==12 || a==15 || a==18 || a==33)
		  cout<<"NO\n";
		else
		  cout<<"YES\n";
	}
	return 0;
}

 

 

E题

链接:https://ac.nowcoder.com/acm/contest/13504/E
来源:牛客网
 

题目描述

小明来到一片海滩上,他很喜欢捡贝壳,但他只喜欢质量为x的倍数的贝壳。

贝壳被排列成一条直线,下标从1到n编号,小明打算从编号为区间[l,r]\left [l,r \right ][l,r]的贝壳中,捡起所有他喜欢的贝壳。你能帮他计算出他能捡多少贝壳吗。

给出一个大小为n(n≤105)n(n\le10^5)n(n≤105)的数组,下标从1到n编号,a1,a2,...ana_1,a_2,...a_na1​,a2​,...an​(ai≤105)(a_i \le 10^5)(ai​≤105))表示贝壳的质量。

给出q(q≤5∗104)q(q\le5*10^4)q(q≤5∗104)次询问,每次询问包含3个整数l,r,x(1≤l≤r≤n,1≤x≤105)l,r,x(1\le l \le r\le n,1\le x\le 10^5)l,r,x(1≤l≤r≤n,1≤x≤105),对于每次询问,输出一行整数,表示这次询问中能捡到的贝壳数。

 

输入描述:

第一行给出两个整数n和q,含义如上所示。

第二行给出n个整数表示a1,a2,...ana_1,a_2,...a_na1​,a2​,...an​

接下来q行,每行3个整数l,r,x,含义如上所示

输出描述:

对于每次询问输出该次询问中能捡到的贝壳数

示例1

输入

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

输出

1
1
1

示例2

输入

10 3 5532 24380 19363 11022 23965 22383 27049 22357 30453 7451 1 6 2 3 10 10 1 10 9

输出

3
0
1

 

题解:

实话讲,我不太会算这题的时间复杂度。

这一题,用vector去保留同一个质量的贝壳在的编号,然后暴力去找就行了。

也挺暴力的。

可以考虑用二分优化一下。

 

#include<iostream>
#include<stdio.h>
#include<vector>

using namespace std;

int n,q,Max;
int a[100005];
vector<int> v[100005];

void read_in()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		v[a[i]].push_back(i);
		Max=max(Max,a[i]);
	}
}

int main()
{
	read_in();
	while(q--)
	{
		int l,r,x,ans=0;
		cin>>l>>r>>x;
		for(int k=x;k<=Max;k+=x)
		for(int i=0;i<v[k].size();i++)
		  if(v[k][i]>=l && v[k][i]<=r)
		    ans++;
		cout<<ans<<endl;
	}
	return 0;
}

 

I题

 

链接:https://ac.nowcoder.com/acm/contest/13504/I
来源:牛客网
 

题目描述

众所周知,一个序列拥有许多非空子序列。

所谓子序列就是在原序列中任意删除 0 个或多个元素,然后保持剩下元素的顺序不变所形成的序列。非空子序列集意味着剩下的子序列不能为空。

比如对于序列[1, 2, 3],它的所有非空子序列为:[1, 2, 3],[1, 2],[1, 3],[2, 3],[1],[2],[3]。再比如序列 [1, 1],它的非空子序列有:[1, 1],[1] (删除了第一个 1),[1] (删除了第二个1) 。

现在母牛哥手里有一个长度为 n 的正整数序列,他现在要为这个序列的所有非空子序列打分。对于一个序列而言,它的评分标准为序列里所有数的乘积(只有一个数的序列,分数就是这个数)。

母牛哥想要知道所有分数的和,但由于结果太大了,所以你只要告诉母牛哥结果对 1000000007 取模即可。

输入描述:

第一行为 n,表示这个序列长度为 n (1 <= n <= 10^6)。

接下来的一行有 n 个数字 a1, a2, …… , an (1 <= ai <= 2 * 10^9) 表示序列的 n 个数字。

输出描述:

一个非负整数,表示结果对 1000000007 取模。

示例1

输入

3
1 2 3

输出

23

示例2

输入

2
1 1

输出

3

 

题解:

这题,用到一个规律,集合的所有子集元素乘积之和。

 

这个就是\left \{a _{1},a _{2}, \cdots a _{n}\right \} 的所有子集元素乘积之和。

 

但是这题注意的是取模的时候,(a%p - b%p )%p  的时候一定要 +p,即为(a%p - b%p + p)%p。

因为a%p 之后 可能会小于b%p 所以相减得到一个小数。

一定要记住!!!!!!!

  

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
int n;
long long ans=1,ot;
long long oo=1000000007;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		long long a;
		scanf("%lld",&a);
		ans= (ans%oo * (a+1)%oo )%oo;
	}
	ot=(ans%oo-1)%oo;
    ot=ot%oo;
	printf("%lld",ot);
	return 0;
}

 

 

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值