2020.02.01【NOIP普及组】模拟赛C组

题目编号 标题
0 怪兽
1 白板
2 序列
3 游戏

T1

题目描述

PYWBKTDA最近正在打怪兽,一个斯拉夫神话中的凶猛怪兽,一个有着多个头的巨大龙状爬行
动物。
开始的时候,怪兽有X个头,你有n种打击方式。如果你选择第i种打击方式,这个神奇的怪兽会减
少min(d i ,cur)个头。这里cur表示当前怪兽拥有的头的数量。但是如果怪兽被打击以后还至少留下
了一个头,那么它就会再长出h i 个头来。当cur = 0或者小于0的时候,怪兽被打败了。
注意,你可以使用任何一种打击方式任何次数,以任何的顺序。
例如,如果当前cur = 10,d = 7,h = 10,那么一次打击以后怪兽就会有13个头了(因为减少了7个
头以后,怪兽还剩下3个头,再加上10个头)。但是如果当前cur = 10,d = 11,h = 100,那么怪兽就被打
败了。

输入

第一行输入是两个整数n和x,分别表示打击的种类和开始时候怪兽的头的数量。
接下来n行, 每行两个整数描述了d i 和h i ,表示第i种打击减少的头的数量和会长出来的头的数量。

输出

输出只有一个整数,表示最少需要打击的次数,如果怪兽无法被打败,就输出−1。

样例输入

【输入样例1】
3 10
6 3
8 2
1 4
【输入样例2】
4 10
4 1
3 2
2 6
1 100
【输入样例3】
2 15
10 11
14 100

样例输出

【输出样例1】
2
【输出样例2】
3
【输出样例3】
-1

数据范围限制

对于50%的数据,1 ≤ n ≤ 10,1 ≤ x ≤ 100,1 ≤ d i ≤ 100,1 ≤ h i ≤ 100。
对于100%的数据,1 ≤ n ≤ 100,1 ≤ x ≤ 10 9 ,1 ≤ d i ≤ 10 9 ,1 ≤ h i ≤ 10 9 。

提示

样例1,你可以使用第一种打击方式,第一次打击以后剩下(10-6+3=7)个头,再进行第2次打击。
样例2,你可以使用第一种打击方式,攻击3次。
样例3,这里你无法打败怪兽。

这道题爆力,

#include<iostream>
#include<cstdio>
using namespace std;
long long m,n,k=2147483647,x,y,d[100100],h[100100];
int main(){
	freopen("monster.in","r",stdin);
	freopen("monster.out","w",stdout);
	cin>>n>>x;
	for(int i=1;i<=n;i++){
		cin>>d[i]>>h[i];
	}
	for(int i=1;i<=n;i++){
		if(d[i]>=x){
			cout<<1;
			return 0;
		}
		y=d[i]-h[i];
		if(y>0){
			long long ans=(x-h[i])/y;
			if((x-h[i])%y!=0)ans++;
			if(ans<k&&ans>0)k=ans;
		}
		if(y<=0){
			if(d[i]>=x){
				cout<<1;
				return 0;
			}
		}
	}
	if(k==2147483647)cout<<-1;
	else{
		cout<<k;
	}
	return 0;
}

T2

题目描述

PYWBKTDA有一块白板,这块白板的四条边分别平行于坐标轴。我们可以假设这块白板的左
下角在(x 1 ,y 1 )位置,右上角在(x 2 ,y 2 )位置。
现在有两块黑板放到白板的上面,这两块黑板的四条边也是平行于坐标轴的。我们可以设第1块
黑板的左下角是(x 3 ,y 3 ),右上角在(x 4 ,y 4 )位置, 第2块黑板的左下角是(x 5 ,y 5 ),右上角在(x 6 ,y 6 )位置。

现在你的任务是来判断,我们从上往下看,是否有白板的部分区域可以被看到。所谓的白板部分
区域被看到的意思是,白板上至少有一个点没有被黑板遮住。

输入

输入第一行有一个整数t,表示数据的组数。
接下来每组数据:
输入的第一行包含4个整数,分别表示x 1 ,y 1 ,x 2 ,y 2 ,即白板的左下角和右上角。
输入的第二行包含4个整数,分别表示x 3 ,y 3 ,x 4 ,y 4 ,即第1块黑板的左下角和右上角。
输入的第三行包含4个整数,分别表示x 5 ,y 5 ,x 6 ,y 6 ,即第2块黑板的左下角和右上角。

输出

输出有t行,对于每组数据,如果有部分白板可以被看到,就输出Y ES,否则就输出NO。

样例输入

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

样例输出

NO
YES
YES
第一个例子中,白板被黑板完全覆盖。
第二个例子中,部分白板可以看到。比如(6.5,4.5)这个点就可以被看到。

数据范围限制

对于50%的数据:
0 ≤ x 1 < x 2 ≤ 100,0 ≤ y 1 < y 2 ≤ 100。
0 ≤ x 3 < x 4 ≤ 100,0 ≤ y 3 < y 4 ≤ 100。
0 ≤ x 5 < x 6 ≤ 100,0 ≤ y 5 < y 6 ≤ 100。
对于100%的数据:
1 ≤ t ≤ 100。
0 ≤ x 1 < x 2 ≤ 10 6 ,0 ≤ y 1 < y 2 ≤ 10 6 。
0 ≤ x 3 < x 4 ≤ 10 6 ,0 ≤ y 3 < y 4 ≤ 10 6 。
0 ≤ x 5 < x 6 ≤ 10 6 ,0 ≤ y 5 < y 6 ≤ 10 6 。

这道题50分爆力,100分可以用离散化
这里,讲一讲离散化
在很多时候,一些不多但很大的数据,会引发OI最致命的错误

TLE

但,离散化可以决绝这个问题
先把这些数排序,再用它们排好序在数列中的位置来做离散化后的值(因为这和它们的大小无关),就完了
代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[500][500],k;
int zb[13],zb2[13];
int main(){
	freopen("sheet.in","r",stdin);
	freopen("sheet.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
		k=0;
		for(int i=1;i<=12;i++){
			cin>>zb[i];
			zb2[i]=zb[i];
		}
		sort(zb2+1,zb2+13);
		for(int i=1;i<=12;i++){
			for(int j=1;j<=12;j++){
				if(zb[i]==zb2[j]){
					zb[i]=j*2;
					break;
				}
			}
		}
		for(int xi=zb[5];xi<=zb[7];xi++){
			for(int yi=zb[6];yi<=zb[8];yi++){
				a[xi][yi]=1;
			}
		}
		for(int xi=zb[9];xi<=zb[11];xi++){
			for(int yi=zb[10];yi<=zb[12];yi++){
				a[xi][yi]=1;
			}
		}
		for(int i=zb[1];i<=zb[3];i++){
			for(int j=zb[2];j<=zb[4];j++){
				if(a[i][j]==0){
					cout<<"YES"<<endl;
					k=1;
					break;
				}
			}
			if(k==1)break;
		}
		memset(a,0,sizeof(a));
		if(k==0)cout<<"NO"<<endl;
	}
	return 0;
}

T3

PYWBKTDA最近在研究一些有趣的数列。
他给你一个无穷序列”112123123412345…”。这个序列是这么构造的,我们先写出1到1的所有整
数,然后写出1到2的所有整数,然后写出1到3的所有整数,这样不断重复进行到无穷。
例如现在前56个数字组成的序列是:
”11212312341234512345612345671234567812345678912345678910”。
我们把序列里面的每个数字从1开始编号,比如编号为1的数字就是1,编号为2的数字也是1,编号
为3的数字是2,编号为20的数字是5,编号为38的数字是2,编号56的数字是0.
现在你的任务是对于题目给出的q个询问,每个询问是k i ,表示问你编号为k i 的数字是多少。

输入

输入格式
第一行是整数q,表示询问的数量。
接下来i行,每行一个整数,表示k i 。

输出

输出共计有q行,第i行的输出表示对应的k i 的询问,显然,每个答案都在0到9之间。

样例输入

【输入样例1】
5
1
3
20
38
56
【输入样例2】
4
2132
506
999999999
1000000000

样例输出

【输出样例1】
1
2
5
2
0
【输出样例2】
8
2
9
8

数据范围限制

对于30%的数据, 1 ≤ k i ≤ 10 5 。
对于70%的数据,1 ≤ k i ≤ 10 9 。
对于100%的数据,1 ≤ k i ≤ 10 18 ,1 ≤ q ≤ 500。

和刘震巨佬说的一样,70分不难,但麻烦

#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
long long m,n,k,x,y,y1;
long long a[10000010];
string s;
int main(){
	freopen("squence.in","r",stdin);
	freopen("squence.out","w",stdout);
	int t;
	cin>>t;
	while(t--){
		cin>>k;
		y=0;
		a[1]=1;
		y1=0;
		while(y1+a[y+1]<k){
			y++;
			int xx=y+1;
			x=y+1;
			y1+=a[y];
			if(a[x]!=0)continue;
			if(x/1000000000!=0){ a[xx]=a[xx]+(x-999999999)*10;x=999999999; }
			if(x/100000000!=0){ a[xx]=a[xx]+(x-99999999)*9;x=99999999; }
			if(x/10000000!=0){ a[xx]=a[xx]+x*8-9999999*8;x=9999999; }
			if(x/1000000!=0){ a[xx]=a[xx]+x*7-999999*7;x=999999; }
			if(x/100000!=0){ a[xx]=a[xx]+x*6-99999*6;x=99999; }
			if(x/10000!=0){ a[xx]=a[xx]+x*5-9999*5;x=9999; }
			if(x/1000!=0){ a[xx]=a[xx]+x*4-999*4;x=999; }
			if(x/100!=0){ a[xx]=a[xx]+x*3-99*3;x=99; }
			if(x/10!=0){ a[xx]=a[xx]+x*2-9*2;x=9; }
			if(x/1!=0){ a[xx]=a[xx]+x; }
		}
		x=k-y1;
		long long i=0,j,k;
		while(x>0){
			i++;
			j=i,k=0;
			while(j!=0){
				k++;
				j=j/10;
			}
			x-=k;
		}
		x+=k;
		while(i!=0){
			char c=(i%10)+48;
			s=c+s;
			i=i/10;
		}
		cout<<s[x-1]<<endl;
		s="";
	}
	return 0;
}

T4

PYWBKTDA很喜欢玩一些游戏,比如算21点。他最近迷上了一款弹珠游戏。
有n个弹珠排成一排,第i个弹珠的颜色是a i 。 PYWBKTDA喜欢把这些弹珠重新排列,使得相
同颜色弹珠都在同一个连续区间。也就是说,如果PYWBKTDA想要把颜色i的全部放在一起,那
么颜色i弹珠的最左边的位置是l,最右边的位置是r,那么所有颜色为i的弹珠的位置只能在l到r之间,
l到r范围内也只能有颜色i的弹珠。
为了达到这个目的,PYWBKTDA将进行如下操作:找到两个相邻的弹珠,把它们交换一下位
置。
现在你的任务是来计算最小的交换次数,使得相同颜色弹珠都在同一区间,在这个区间内,同
种颜色的弹珠的位置是无关紧要的。

输入

输入的第一行是一个整数n,表示弹珠的数量。
输入的第二行有n个整数a i ,表示第i个位置上弹珠的颜色。

输出

输出只有一个整数,表示最少的交换次数。

样例输入

【输入样例1】
7
3 4 2 3 4 2 2
【输入样例2】
5
20 1 14 10 2
【输入样例3】
13
5 5 4 4 3 5 7 6 5 4 4 6 5

样例输出

【输出样例1】
3
【输出样例2】
0
【输出样例3】
21

数据范围限制

对于20%的数据,1 ≤ n ≤ 100,1 ≤ a i ≤ 2。
对于60%的数据,1 ≤ n ≤ 100000,1 ≤ a i ≤ 10。
对于100%的数据,1 ≤ n ≤ 100000,1 ≤ a i ≤ 20。

提示

样例1,在颜色序列[3,4,2,3,4,2,2]中,我们可以把第3个和第4个交换一下,然后把第2个和第3个交换
一下,最后把第4个和第4个交换一下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值