模拟习题练习2

time:2.5

一、

题目描述

给定一个 N × M 的矩阵 A,请你统计有多少个子矩阵 (最小 1 × 1,最大 N × M) 满足子矩阵中所有数的和不超过给定的整数 K? 

输入格式

第一行包含三个整数 N, M 和 K. 

之后 N 行每行包含 M 个整数,代表矩阵 A.

输出格式

一个整数代表答案。

样例输入

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

样例输出

19

1、简单的暴力算法:

直接循环每个元素并包含该元素进行行循环,列循环若超过目标值,则终止。

2.改进算法:

将列元素相加,并存储在二维数组中

#include <stdio.h>
#include <iostream>
using namespace std;
int s[505][505];
int main()
{
	int a = 0, b = 0, c = 0;
	cin >> a >> b >> c;
	for (int i = 1; i <= a; i++)
	{
		for (int j = 1; j < b; j++)
		{
			cin >> s[i][j];
			s[i][j] += s[i - 1][j];
		}
	}
		long long int res = 0;
		for (int i = 1; i < a; i++)
		{
			for (int j = i; j <= a; j++)
			{
				for (int left = 1, right = 1, sum = 0; right <= b; right++)
				{
					sum += s[j][right] - s[i - 1][left];
					while (sum>c)
					{
						sum -= s[j][left] - s[i - 1][left];
						left++;

					}
					res += right - left + 1;
				}
			}
		}

		printf("%lld", res);
	return 0;
}

二、

题目 2657:

修剪灌木

时间限制: 3s 内存限制: 320MB 提交: 8139 解决: 4285

题目描述

爱丽丝要完成一项修剪灌木的工作。有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

输入格式

一个正整数 N ,含义如题面所述。

输出格式

输出 N 行,每行一个整数,第i行表示从左到右第 i 棵树最高能长到多高。

样例输入

3

样例输出

4
2
4

提示

对于 30% 的数据,N ≤ 10. 对于 100% 的数据,1 < N ≤ 10000.

#include<stdio.h>
#include<iostream>
using namespace std;
int max(int a, int b)
{
	return a > b ? a : b;
}
int main()
{
	int num;
	cin >> num;
	for (int i = 1; i <= num; i++){
		printf("%d\n", max(i - 1, num - i) * 2);
	}

	return 0;
}

三、

题目 2656:

刷题统计

时间限制: 3s 内存限制: 320MB 提交: 29063 解决: 4749

题目描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题?

输入格式

输入一行包含三个整数 a, b 和 n.

输出格式

输出一个整数代表天数。

样例输入

10 20 99

样例输出

8

提示

对于 50% 的评测用例,1 ≤ a, b, n ≤ 106 . 对于 100% 的评测用例,1 ≤ a, b, n ≤ 1018 .

1.会因为运行时间拿不到满分

#include<stdio.h>
#include<iostream>
using namespace std;
int a = 0, b = 0, n = 0;
int j[100000000];
int d = 0;
int main()
{
	while (1)
	{

		int sum = 0;
		cin >> a >> b >> n;
		if (a < b)
		{
			d = n / a;
		}
		else if (a >= b)
		{
			d = n / b;
		}
		for (int i = 0; i < (d + 3); i++)
		{
			if (((i + 1) % 7) <= 5 && ((i + 1) % 7) != 0)
			{
				j[i] = a;
			}
			else if (((i + 1) % 7) == 0 || ((i + 1) % 7) == 6)
			{
				j[i] = b;
			}
		}
		int num = 0;
		while (sum < n)
		{
			sum += j[num];
			num++;


		}
		printf("%d", num);
	}
	
	return 0;
}

2.

#include<stdio.h>
int main()
{
    long long int a,b,n,sum=0;
    scanf("%lld%lld%lld",&a,&b,&n);
    long long int flag=n/(a*5+b*2);//几个完整的周数
    n-=(a*5+b*2)*flag;
    sum+=flag*7;
    if(n/a<=5)
    {
        sum+=n/a;
        if(n/a==5)
        {
            sum+=(n-5*a)/b+(n-5*a-b)%1;
             
        }
        else if(n%a>0)
        {
            sum++;
        }
    }else{
        sum+=5+(n-5*a)/b;
        if((n-5*a)%b>0)
        {
            sum++;
        }
    }
    printf("%lld",sum);
    return 0;
}

四、

小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下, 在一个二维平面上放置着 n 个炸雷,第 i 个炸雷 (xi , yi ,ri) 表示在坐标 (xi , yi) 处存在一个炸雷,它的爆炸范围是以半径为 ri 的一个圆。

为了顺利通过这片土地,需要玩家进行排雷。玩家可以发射 m 个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第 j 个排雷火箭 (xj , yj ,rj) 表示这个排雷火箭将会在 (xj , yj) 处爆炸,它的爆炸范围是以半径为 rj 的一个圆,在其爆炸范围内的炸雷会被引爆。同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。现在小明想知道他这次共引爆了几颗炸雷? 

你可以把炸雷和排雷火箭都视为平面上的一个点。一个点处可以存在多个炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。

输入格式

输入的第一行包含两个整数 n、m.

接下来的 n 行,每行三个整数 xi , yi ,ri,表示一个炸雷的信息。

再接下来的 m 行,每行三个整数 xj , yj ,rj,表示一个排雷火箭的信息。

输出格式

输出一个整数表示答案。

样例输入

2 1
2 2 4
4 4 2
0 0 5

样例输出

2
#include <stdio.h>
struct node
{
	int x, y, d;
} a[100000], p[100010];
int vis[100000], t, n;
long long juli(int x, int y, int xx, int yy)
{
	return (long long)((x - xx)*(x - xx) + (y - yy)*(y - yy));
}
int main()
{
	int i, j, m;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= n; i++)
		scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].d);
	for (i = 1; i <= m; i++)
		scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].d);

	int l = 0, r = m + 1;
	while (++l<r)
	{
		for (i = 1; i <= n; i++)
		{
			//用vis来记录是否已经入队
			if (vis[i] == 0 && juli(p[l].x, p[l].y, a[i].x, a[i].y) <= (long long)p[l].d*p[l].d)//要是在范围内就加入队列变成排雷火箭
			{
				vis[i] = 1;
				t++;
				p[r++] = a[i];
			}
		}
	}
	printf("%d", t);
	return 0;
}

改进(用二分法查找来防止内存超限)

#include<stdio.h>
struct node
{
	int x, y, d;
} a[100000], p[100010];
int vis[100000], t, n;
int kuai(int xx, int yy)//给炸雷的x排序
{
	int i = xx, j = yy;
	struct node t = a[(i + j) / 2];//取中
	do
	{
		while (a[i].x>t.x) j--;
		if (i <= j)
		{
			struct node m = a[i];
			a[i] = a[j];
			a[j] = m;
			i++;
			j--;
		}
	} while (i <= j);
	if (xx<j) kuai(xx, j);
	if (i<yy) kuai(i, yy);
}

long long juli(int x, int y, int xx, int yy)
{
	return (long long)((x - xx)*(x - xx) + (y - yy)*(y - yy));
}

int fun(int sum)//二分法查找在横坐标为你sum位置的点排在炸弹的第几位
{
	int r = n, l = 1, mid;
	while (l<r)
	{
		mid = (r + l) / 2;
		if (sum <= a[mid].x) r = mid;
		else l = mid + 1;
	}
	return l;
}

int main()
{
	int i, j, m;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= n; i++)
		scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].d);
	for (i = 1; i <= m; i++)
		scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].d);

	kuai(1, n);

	int l = 0, r = m + 1;//炮弹数量
	while (++l<r)
	{
		int xx, yy;
		xx = p[l].x - p[l].d, yy = p[l].x + p[l].d;//表示左右的范围
		xx = fun(xx - 1), yy = fun(yy + 1);//可能会出现相等的数据,而只包含到其中的一个,所以扩展所查找的范围即可

		for (i = xx; i <= yy; i++)//搜寻在该范围内的炸雷//缩小了搜索范围
		{
			if (vis[i] == 0 && juli(p[l].x, p[l].y, a[i].x, a[i].y) <= (long long)p[l].d*p[l].d)//要是在范围内就加入队列变成排雷火箭
			{
				vis[i] = 1;
				t++;
				p[r++] = a[i];
			}
		}
	}
	printf("%d", t);
	return 0;
}


五、

描述

小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。

河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降 1,当石头的高度下降到 0 时小青蛙不能再跳到这块石头上(某次跳跃后使石头高度下降到 0 是允许的)。

小青蛙一共需要去学校上 x 天课,所以它需要往返 2x 次。当小青蛙具有一个跳跃能力 y 时,它能跳不超过 y 的距离。

请问小青蛙的跳跃能力至少是多少才能用这些石头上完 x 次课。

输入格式

输入的第一行包含两个整数 n, x,分别表示河的宽度和小青蛙需要去学校的天数。请注意 2x 才是实际过河的次数。

第二行包含 n − 1 个非负整数 H1, H2, · · · , Hn-1,其中 Hi > 0 表示在河中与小青蛙的家相距 i 的地方有一块高度为 Hi 的石头,Hi = 0 表示这个位置没有石头。

输出格式

输出一行,包含一个整数,表示小青蛙需要的最低跳跃能力。

样例输入

5 1
1 0 1 0

样例输出

4

提示

由于只有两块高度为 1 的石头,所以往返只能各用一块。第 1 块石头和对岸的距离为 4,如果小青蛙的跳跃能力为 3 则无法满足要求。所以小青蛙最少需要 4 的跳跃能力。 

对于 30% 的评测用例,n ≤ 100;

对于 60% 的评测用例,n ≤ 1000;

对于所有评测用例,1 ≤ n ≤ 105 , 1 ≤ x ≤ 109 , 1 ≤ Hi ≤ 104。

#include<stdio.h>
#include<iostream>
using namespace std;
const int mmax = 1e5 + 100;
int hei[mmax];  //用来存放特定位置石头的高度
int front[mmax];  //用来存放前缀和 
typedef long long ll;
ll ans;    //最后答案 
ll n, x;
bool isok(ll mid)
{
	//最关键的是--每一个长度为 i 的区间的石头高度和都大于等于2x吗
	for (ll i = 1; i <= n - mid; ++i)
	{
		ll r = i + mid - 1;
		if (front[r] - front[i - 1] < 2 * x)
			return false;
	}
	return true;
}
int main()
{
	while (1)
	{

		cin >> n >> x;//河的宽度与上学的天数
		for (int i = 1; i <= n - 1; ++i)
		{
			cin >> hei[i];
			front[i] = front[i - 1] + hei[i];
		}
		int le = 1;
		int ri = n;
		int mid = le + (ri - le) / 2;
		while (le < ri)
		{
			if (isok(mid))//在前半段范围
			{
				ans = mid;
				ri = mid - 1;
				mid = le + (ri - le) / 2;
			}
			else{//在后半段范围
				le = mid + 1;
				mid = le + (ri - le) / 2;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值