计蒜客信息学普及组赛前模拟#1(10-26)

五迷三道 提交于 2019-12-02 12:15:20

计蒜客信息学普及组赛前模拟#1(10-26)

 A.爬山

DD 现在想去爬山,她定义从第 i 座山到第 i+1座山的疲劳度是 |a[i]-a[i+1]|, 现在给定 n 座山,初始状态下 DD 在第一座山上,她想知道整个爬山过程中单次疲劳度最大是多少

输入格式

第一行给定一个整数表示 n

第二行 n 个整数,第 ii个表示 ai​

输出格式

输出单次疲劳度最大值是多少

数据范围

对于 30% 的数据,2≤n≤5000

对于另外20% 的数据,保证所有ai​ 都相同

对于 100% 的数据,2≤n≤500000,1≤ai​≤1e9

输出时每行末尾的多余空格,不影响答案正确性

样例输入

6
1 100 2 200 3 300

样例输出

297

解题思路:只用输出单次疲劳的最大值即可。所以我们设x,y,将a1的输入独立出来,然后对于其后的每一次输入,(x为当次输入的值,y为上次输入的值),比较他们的差,选取最大值即可。代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,j,k) for(int i = (j); i <= (k); i++)
#define sf(n) scanf("%d",&n)
#define pf(n) printf("%d\n",n)
inline int mx(int a,int b){
    return a>b?a:b;
}
int n,x,sum=-1,y,t;
int main()
{
	sf(n);
	sf(x);
	y=x;
	rep(i,2,n){
		sf(x);
		if(y>x)t=y-x;
		else t=x-y;
		y=x;
		sum=mx(sum,t);//若该次疲劳值比之前的最大值大,更新疲劳值
	}
	pf(sum);
	return 0;
}

B.纸片

现在给定 l,r ,DD 拿到了 r-l+1张纸片,上面分别写着 l,l+1,l+2...r-1,r现在把它们按顺序连在一起看,变成 l(l+1)(l+2)...(r-1)r,例如 l=2,r=6 连在一起后得到 23456,DD 现在想知道这个数是不是 9 的倍数

输入格式

第一行一个整数 TT表示数据组数

接下来 T 行,每行两个整数分别表示 l,r

输出格式

对于每次询问,如果是 9 的倍数输出Y,反之输出N

数据范围

对于 30% 的数据,1≤l≤r≤10

对于 50% 的数据,1≤l≤r≤106

对于 100% 的数据,1≤T≤10000,1≤l≤r≤1e12

输出时每行末尾的多余空格,不影响答案正确性

样例输入

3
2 4
2 5
2 7

样例输出

Y
N
Y

解题思路:题目让求数 l(l+1)(l+2)...(r-1)r 是否为9的倍数,逐个判断铁定超时,但是我们可以利用9的倍数的特性进行简化,而且l和r之间是连续的,这就又给了另一个操作空间。对于9的倍数,有一个和3的倍数类似的特性,若一个数x的各个数位之和是9的倍数则x为9的倍数;同样的假设x=n*9,则对于 x+1+x+2+x+3 + .... x+8=y,(1+2+3+4+5+6+7+8)=36=9*4,不难推出在两个9的倍数之间的8个数的数位和也必为 9的倍数,所以,问题就变为了求l到(l到r间最小的9的倍数的各个数的数位和 与 r 到(l到r间)最大的9的倍数的各个数位的数位和 的和是否为9的倍数,若是则输出Y,否则输出N。需要注意的是,对与(r-l)和(r<9)的情况要区别对待。代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define sf(n) scanf("%d",&n)
LL l,r,sum,num;
int main()
{
	int T;
	sf(T);
	while(T--){
		scanf("%lld%lld",&l,&r);
		sum=0;//初始化数位和的值
        if(l%9==0&&r%9==0)sum=9;//l和r均为9的倍数,则一定有l (l+1) ...(r-1)r为9的倍数
        else if(r<=9||r-l<9){//特殊情况,单独列出
            for(LL i=l;i<=r;i++){
                LL j=i;
                while(j>0){
                    sum+=j%10;
                    j/=10;
                }
            }
        }
        else {
            for(LL i=l;i<r;i++){//算出l到最小的9的倍数间的数位和
                if(i%9==0)break;
                LL j=i;
                while(j>0){
                    sum+=j%10;
                    j/=10;
				}
            }
            for(LL i=r;r>l;i--){//算出r到最大的9的倍数间的数位和
                if(i%9==0)break;
                LL j=i;
                while(j>0){
                    sum+=j%10;
                    j/=10;
				}
            }
        }
		if(sum%9==0)cout<<"Y\n";
		else cout<<"N\n";
	}
	return 0;
}

c.颜色

现在给定一张 n*m 的网格图,网格中如果当前这个有颜色,那么 col[i][j]是一个非零的数字,如果这个点没有颜色,那么 col [i][j]是 0,现在 DD 想知道,自己如果只能在上下左右相邻的且都是有颜色的格子上移动的情况下,自己最多能碰到多少种颜色

输入格式

第一行两个整数分别表示 n,m

接下来 n 行,每行 m 个整数,分别表示 col[i][j]

输出格式

输出 DD 最多能碰到多少种颜色

数据范围

对于 30% 的数据,1≤n,m≤50

对于另外 20% 的数据,1≤coli,j​≤1e6

对于 100% 的数据,1≤n,m≤1000,1≤coli,j​≤1e9

输出时每行末尾的多余空格,不影响答案正确性

样例输入

5 5
1 2 3 4 0
0 0 0 0 7
1 2 2 1 0
0 0 0 3 4
6 0 0 5 0

样例输出

5

解题思路:比较直接的搜索题,输入完后遍历地图,没发现一个带颜色的位置,则以该位置为出发点进行遍历,遍历过程中每到一个点就将mp[i][j]设为0(假设两个位置是联通的,只用走一个点就可以了,其他的点再走结果也是一样的);但题中要求的是最多能碰到多少种颜色,所以不能直接用计数器++;仔细观察可以发现地图中出现的非0数字就是 一种颜色,如果能每次遍历到一个有颜色的点就把它取出,最后去重统计个数然后比较大小,不就能得出最多碰到的颜色了吗?而stl中的set可以有很好的发挥。代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<int> vi;
typedef pair<int,int> ii;
#define inf 1e9
#define F first
#define S second
#define dbg(x) cout<<#x<<" value : "<<x<<"\n";
#define rep(i,j,k) for(int i = (j); i <= (k); i++)
#define rep__(i,j,k) for(int i = (j); i < (k); i++)
#define per(i,j,k) for(int i = (j); i >= (k); i--)
#define per__(i,j,k) for(int i = (j); i > (k); i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define sf(n) scanf("%d",&n)
#define stf(n,m) scanf("%d%d",&n,&m)
#define pf(n) printf("%d\n",n)
#define slf(n) scanf("%lld",&n)
#define plf(n) printf("%lld\n",n)
priority_queue<int,vector<int>,greater<int> > q;
const int N=1e3+10;
const int mod=1e9+7;
int n,m,a[N][N],num;
set<int> w;
int dx[4][2]={1,0,-1,0,0,1,0,-1};//移动数组
inline bool txt(int x,int y){//判断是否越界
	return x>0&&x<=n&&y>0&&y<=m;
}
inline int mx(int x,int y){
	return x>y?x:y;
}
void dfs(int x,int y){
	a[x][y]=0;//每访问一个位置,就把它设为没有颜色
	for(int i=0;i<4;i++){
		int nx=x+dx[i][0];
		int ny=y+dx[i][1];
		if(txt(nx,ny)){
			if(a[nx][ny]!=0){//如果该位置有颜色
                w.insert(a[nx][ny]);//将颜色编号加入set
				dfs(nx,ny);//从该位置进行新的移动
			}
		}
	}
}
void slove(){
	rep(i,1,n){
		rep(j,1,m){
			if(a[i][j]==0)continue;
			else {
				w.insert(a[i][j]);
				dfs(i,j);
				num=mx(w.size(),num);//根据碰到的颜色种类多少来决定是否更新num的值
                w.clear();//在某次遍历后清空set
			}
		}
	}
	cout<<num<<endl;
}
int main()
{
	stf(n,m);
	rep(i,1,n){
		rep(j,1,m){
			sf(a[i][j]);
		}
	}
	slove();
	return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!