2017 南海区区赛

2017区赛 解题报告

 

第一题元音字母(vowel)

【问题描述】

给你一个所有字符都是字母的字符串,请输出其中元音字母的个数。(提示:二十六个字母中的五个元音字母是a,e,i,o,u; 所有字符有大小写区别。)

【输入格式】

仅一行,包括一个字符串。

【输出格式】

输出一个整数,如题所述。

【输入样例】

helloworld

【输出样例】

3

【数据规模】

对于100%的数据,字符串长度小于等于10^6。

这题比较水,就是看一个字符串里面有多少个元音字母。学过字符串都能够做出来,我就不多说了。不过要注意的一点是,有大小写的区分,意思是不仅仅是小写,大写字母中的元音字母也是要计算的。后来我在检查的时候发现了这一点。时间复杂度O(10^6)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
string s;
int ans;
int main()
{
	freopen("vowel.in","r",stdin);
	freopen("vowel.out","w",stdout);
	cin>>s;
	for(int i=0;i<s.size();i++)
	{
		if(s[i]==‘A‘||s[i]==‘E‘||s[i]==‘I‘||s[i]==‘O‘||s[i]==‘U‘||s[i]==‘a‘||s[i]==‘e‘||s[i]==‘o‘||s[i]==‘u‘||s[i]==‘i‘) ans++;
	}
	cout<<ans<<endl;
	return 0;
}

  

第二题直角坐标系(coordinates)

【问题描述】

给你n 个平面上的点,请你绘制出一个直角坐标系。对于原点,用‘ + ‘表示;对于y 坐标轴,用‘ |‘表示(除去原点和n 个点的位置);对于x 坐标轴,用‘ - ‘表示(除去原点和n 个点的位置);对于n 个平面上的点,用‘ * ‘表示;所有其他点,用‘ . ‘表示。为了更好地理解,请参照样例。

【输入格式】

第一行包括一个正整数n。

接下来n 行,每行两个整数x, y,表示点的坐标。

【输出格式】

一个直角坐标系。其中,第一行的y 坐标为所有点的y 坐标和0 中的最大值;最后一行的y 坐标为所有点的y 坐标和0 中的最小值;第一列的x 坐标为所有点的x 坐标和0 中的最小值;最后一列x 坐标为所有点的x 坐标和0 中的最大值。详见样例。

【输入样例1】

8

-105

-73

-42

-94

01

6-1

30

8-3

【输出样例1】

*. . . . . . . . . | . . . . . . . .

.* . . . . . . . . | . . . . . . . .

.. . * . . . . . . | . . . . . . . .

.. . . . . * . . . | . . . . . . . .

.. . . . . . . . . * . . . . . . . .

----------+ -- * -----

.. . . . . . . . . | . . . . . * . .

.. . . . . . . . . | . . . . . . . .

.. . . . . . . . . | . . . . . . . *

【输入样例2】

5

12

53

21

55

33

【输出样例2】

|. . . .*

|. . . . .

|. . * . *

|* . . . .

|. * . . .

+-----

【数据规模】

对于30%的数据,1<=x<=100,1<=y<=100

对于100%的数据,1<=n<=250, 且x,y 的绝对值都不超过100,所有的点两两不同。

这题是一个比较简单的模拟,在输入时标记哪个地方有点,用v数组标记。但是,因为有负半轴的缘故,所以不能直接标记v[x][y],要把x和y都加一个偏移量,因为他们的绝对值都不超过一百,所以加100就够了。

同时在输入时记录下最小和最大的x、y分别是多少。

但是,通过第二个样例可以得知,必须要画出一个坐标轴,不然怎么能算是直角坐标系呢。所以,最小和最大的x、y都要与0取max(min)

然后按一定的次序输出即可。时间复杂度O(x*y)

第三题折纸(folding)

【问题描述】

现有一个W*H的矩形纸张,求至少要折多少次才能使矩形纸张变成w*h的矩形纸张。注意,每次的折痕都要平行于纸张的某一条边。

【输入格式】

第一行包括两个整数W,H。

第二行包括两个整数w,h。

【输出格式】

输出一个整数,表示至少需要折的次数。若无解,则输出-1。

【输入样例1】

27

22

【输出样例1】

2

【输入样例2】

55

16

【输出样例2】

-1

【输入样例3】

106

48

【输出样例3】

2

【数据规模】

对于20%的数据,W=w且H,h<=3

对于100%的数据,1<=W,H,w,h<=10^9

从这题开始,请注意:前方高能!

比赛的时候,我在纸上画了几下,发现当边长是W时,把它对折一下为W/2,如果期望达到的w在W和W/2的范围之内,那么就是可以的,否则,就要折成W/2。

但是看到了最后一个样例,他们的边长需要反过来才能够折,于是自认为很“机智”地就用swap把大小调整好,大对大,小对小。事实证明是个大错误。

错误点get

1、 不能直接变成W/2,因为当是7的时候,7/2=3,但是并不能折到3,应该最小是4。所以应该是(W+1)/2,同样的,用偶数实验也是可行的。

2、 至于大对大,小对小的思路显然是想少了。赛后同学给我举了个例子,5 7折成4 5。如果是用我的方法,那么5折成4要折一次,7折成5也要折一次,一共就是两次。

但如果是5对5,那么根本不用折,7对4,这一次就可以了。最优解应该是一次。

我看似很有道理的理论就over了。

正解其实和这个差不了多少,就是分别算一下两种对应的情况,取一个min为最优解即可。

时间复杂度 O(log(10^9))

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
using namespace std;
const int oo=10000000;
int W,H,w,h,lans,ans2=oo;
int update(int x,int y)
{
	int ans=0;
	int x2=x;
	while(x2>y)
	{
		ans++;
		x2=(x2+1)/2;
	}
	return ans;
}
int main()
{
	scanf("%d%d",&W,&H);
	scanf("%d%d",&w,&h);
	if((w>W&&w>H)||(h>W&&h>H))
	{
		cout<<-1<<endl;
		return 0;
	}
	if(W>=w&&H>=h)
	{
		lans+=update(W,w);
		lans+=update(H,h);
		ans2=min(lans,ans2);
	}
	lans=0;
	swap(W,H);//交换一下 再算一次
	if(W>=w&&H>=h)
	{
		lans+=update(W,w);
		lans+=update(H,h);
		ans2=min(ans2,lans);
	}
	printf("%d",ans2);
	return 0;
}

  

第四题两个数(twonum)

【问题描述】

现有两个人, 若第一个人当前手中的数为w1,则下一秒他手上的数将会变成(X1 *W1+Y1 ) mod m;若第二个人当前手中的数为 w2,则下一秒他手上的数将会变为(X2*W2+Y2 )mod m(a mod b 表示a 除以b 的余数)。第0 秒,两个人手上的数分别为h1, h2; 请求出最快在第几秒,第一个人手上的数为a1,且第二个人手上的数为a2。若不可能,则输出-1。

【输入格式】

第一行为一个正整数T,表示数据组数。

对于接下来的每一组数据, 第一行为一个正整数m,第二行包括两个整数h1, a1,第三行包括两个整数x1, y1,第四行包括两个整数h2, a2,第五行包括两个整数x2, y2。

【输出格式】

对于每一组数据,输出一行,一个整数,如题所述。

【输入样例】

2

5

42

11

01

23

1023

12

10

12

11

【输出样例】

3

-1

【数据规模】

对于30%的数据, m<=1000

对于100%的数据,

T<=5,  h1不等于 a1且 h2不等于 a2,

2<=m<=106 , 0<=h1,a2, x1, y1, h2, a2, x2, y2<m

这题在所有题目里面,是最复杂的,虽然看上去好像就是一个简单的模拟,然而事实证明,我想少了。

首先,要找到循环节。可是循环节怎么找呢?用while循环找。分别用va和vb记录第一和第二个人出现每一个数字的秒数。

一开始初始化为-1,如果已经出现过,那么说明出现了循环,break。循环节的长度cir1则为当前的i-va[],同样的另外一个人出现循环节的长度cir2也为j-vb[]

如果两个va[a1]和va[a2]都为-1,说明不在循环以内出现,那么就输出-1。如果va[a1]==va[a2]都相等,那就最好不过了,直接输出。

接下来,问题就来了,我们分为几种情况。

1、如果va[a1]在循环节里面并且vb[a2]在循环节外面,那么vb[a2]要大于等于va[a1]不然它们是无法在同一秒内出现的。再看一下vb[a2]-va[a1]能否被第一个人的循环的长度cir1整除。如果符合条件输出vb[a2]。

2、同理,vb[a2]在循环节里面并且va[a1]在循环节外面的情况也是一样的。

3、最后一种情况也是最复杂的(我还是一脸蒙,尝试解释)。va[a1]在循环节里面并且vb[a2]在循环节里面。

有解:分别计算出两个循环节的最大公因数cd,如果他们两个的差除以cd除不尽,那么无解。枚举第一个人,判断是否符合va[a1]>=vb[a2],并且他们的差值是否能被cir2(vb[a2]循环的长度)整除。

听老师讲完这题以后,我只能说,有点厉害

int gcd(int a,int b)
{
	while(b)
	{
		int c=a%b;
		a=b;
		b=c;
	}
	return a;
}
int main()
{
	long long t,a1,b,mod,h1,x1,y1,h2,a2,x2,y2;
	cin>>t;
	while(t--)
	{
		cin>>mod>>h1>>a1>>x1>>y1>>h2>>a2>>x2>>y2;
		memset(va,-1,sizeof(va));memset(vb,-1,sizeof(vb));
		va[h1%mod]=0;vb[h2%mod]=0;
		long long i,j;i=j=1;
		while(1)
		{
			h1=(x1*h1+y1)%mod;
			if(va[h1]==-1)
			{
				va[h1]=i;
				i++;
			}
			else break;
		}//分别算出在哪个地方循环
		while(1)
		{
			h2=(x2*h2+y2)%mod;
			if(vb[h2]==-1)
			vb[h2]=j;
				j++;
			}
			else break;
		}
		if(va[a1]==-1||vb[a2]==-1) cout<<-1<<endl;
		else if(va[a1]==vb[a2]) cout<<va[a1]<<endl;
			else{
			long long cir1=i-va[h1];
			long long cir2=j-vb[h2];
			if(va[h1]>va[a1])
			{
				if(vb[h2]>vb[a2]) cout<<-1<<endl;
				else{
					long long cnt2=vb[a2];
					if((va[a1]-cnt2>=0)&&((va[a1]-cnt2)%cir2==0))
						cout<<va[a1]<<endl;
						else
						cout<<-1<<endl;
				}
			}
			else{
				if(vb[h2]>vb[a2])
				{
					long long cnt1=va[a1];
					if((vb[a2]-cnt1>=0)&&((vb[a2]-cnt1)%cir1==0))
						cout<<vb[a2]<<endl;
						else
						cout<<-1<<endl;
				}
				else{

					int cnt=vb[a2]-va[a1];
					int cd=gcd(cir1,cir2);
					if(cnt%cd!=0) cout<<-1<<endl;
					else{
						long long cnt1=va[a1];
						long long cnt2=vb[a2];
						while(1)
						{
							if((cnt1>=cnt2)&&((cnt1-cnt2)%cir2==0))
							{
								cout<<cnt1<<endl;
								break;
							}
						else cnt1+=cir1;
						(此处省略6个括号)
	return 0;
}

  

第五题取值(numbers)

【问题描述】

现给你两个正整数n, m。请问有多少种对整数x1,x2,…xn的取值,使得等式x1+x2+x3+xn=m成立。你的赋值必须满足0 ≤ x1 ≤ x2 ≤ ... ≤ xn 。例如,当 m =3, n = 2 时, 共有 2 种取法,分别为( x1,x2 )=( 0,3 )或( 1,2 )。请输出答案除以10^8 + 7的余数。

【输入格式】

第一行为一个正整数T,表示数据组数。

接下来T 行,每行两个正整数,分别为m 和n。

【输出格式】

输出T 行,分别表示对每一组数据的答案除以10^8 + 7的余数。

【输入样例】

2

3 2

7 3

【输出样例】

2

8

【数据规模】

对于10%的数据,1<=n<=m<=10

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

对于50%的数据,1<=n<=m<=100

对于100%的数据,T<=20,1<=n<=m<=300

这题在当时我没有做出来,用了深度搜索,我没怎么考虑时间复杂度,而且也没有什么好的想法,于是草草地就交了,严重超时,估计只有五分。

老师教我们用递归的方法。首先,把分配数字的问题形象化为分配小球。

ans[7][5]为把7(m)个小球放入5(n)个篮子里的方案数,注意题目已经说到x1≤x2≤x3,也就是说,每一个篮子里面的球的数量都是递增的。

按经验来说,放球这种问题都会有两种情况,分别是放或者不放。

1、不放,那么就分为把7个球放到5-1=4个篮子里的子问题;

2、放,那么后面的每一个篮子至少都要有一个球(因为是递增的关系),所以,就要把7-5=2个球,放进5个篮子里 的方案数了。

最后的方案数就是把这两种情况都加起来即可。

不过要注意边界问题,如果没有球,那么无论放进几个篮子里面的方案数都只有1。那么如果只有一个篮子,不管往里面放几个球的方案数也是1。

同时还要注意一种情况,当球的数量(m)比篮子的数量(n)小的时候,是直接为m个球放入m个篮子的方案数,因为它的个数要从小到大,所以,如果你前面摆不满,后面不能摆。

为了节省时间,还要用到记忆化搜索。

时间复杂度 O(n^2)

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=100000007;
int r,m,n,ans[305][305];
void init()
{
	memset(ans,0,sizeof(ans));//每次都要初始化清零
}
int f(int m,int n)
{
	if(m==0||n==1) return 1;//边界处理
	if(m<n) return f(m,m)%mod;
	if(ans[m][n]!=0) return ans[m][n]%mod;//记忆化搜索
	return ans[m][n]= (f(m,n-1) % mod + f(m-n,n) %mod ) % mod;
}
int main()
{
	cin>>r;
	while(r)
	{
		r--;
		init();
		cin>>m>>n;
		ans[m][n]=f(m,n);
		cout<<ans[m][n]<<endl;
	}
	return 0;
}

  

第六题数对(pairs)

【问题描述】

给定一个正整数n。现在有一个有数对(a, b)组成的序列,其中1<=a<=n,|b|<=n。|b|表示b的绝对值。该序列称为优美的序列,当且仅当以下条件同时满足:

1. 所有的数对都不相同;

2. 对于每一个数对(a,b),a 和|b|不相同。

3. 对于每一个数对(a, b),若b>0,则它之前一定存在一个数对(a‘,b‘)满足a‘=b 且b‘=0;

4. 对于每一个数对(a, b),若b<0,则它之前一定不存在一个数对(a‘,b‘)满足a‘=-b 且b‘=0;

5. 对于所有相邻的数对(a1,b1),(a2,b2),满足b1 和b2 不同时为正数且不同时为负数且不同时为0;

请你求出最长的优美的序列的长度。

例如,当n=2 时,其中一个最长的优美的序列为(2 ,-1 ),(1 ,0 ),(1 ,-2 ),(2 ,1 ),(2 ,0 ),(1 ,2 ),长度为6。

【输入格式】

仅一行,一个正整数n。

【输出格式】

输出一个整数,如题所述。

【输入样例】

2

【输出样例】

6

【数据规模】

对于20%的数据,n<=4

对于80%的数据,n<=10^6

对于100%的数据,n<=10^8

一开始看这题的时候,瞬间就蒙掉了,限制条件比较多,而且我把第二个不存在看成了存在,也耗了不少时间,审题要仔细啊。

这题的条件比较复杂。我们不妨把每一组数对看成一个平面直角坐标系上面的点。比如样例中的(2,-1)则为横坐标为2,纵坐标为-1的点。

那么在坐标系上,要求分别为

1、不能为(1,-1)(1,1)(2,-2)(2,2),因此可得,不能在两个角的平分线上。

2、如果纵坐标y大于0,那么在x轴上一定要存在一个x=y的点。

3、如果纵坐标y小于0,那么在x轴上x=y的点不存在。

4、不能一直区正半轴或x轴 或下半轴

我们先从样例给出的2开始看起。

(颜色没搭好)

红点表示对角线,也就是条件1,是不可以有点的位置。因为2的范围太小,不容易观察出规律,再考虑一下3。

通过上图可以发现,应该先确定下面的点,尽量把下面哪那一行区满,然后再取x轴上的点,并且只有取了x轴上的点以后再能取上半轴的点。

我们会发现,只有下半轴第一行和上半轴最上面一行的有一个点,并且x坐标轴上有n个点,其余的都只有n-1个点。

因此很容易可以推出:

ans=2+n+(n-1)*(n-1)*2=2*n*n-3*n+4

但是有特例,当n=1时,ans=1

所以,貌似这就是一个找规律的题目,但是能否做出来的关键是,能否从数对转移到坐标轴。

时间复杂度:O(1)

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
long long n;
long long ans;
int main()
{
	cin>>n;
	if(n==1)
	{
		cout<<1<<endl;
		return 0;
	}//判断特例
	ans=2*n*n-3*n+4;
	cout<<ans<<endl;
	return 0;
}

  代码很短,我也被惊到了。

时间: 2024-10-12 02:55:34

2017 南海区区赛的相关文章

ACM总结——2017湖南省省赛总结

2017省赛已经结束了2天了,今天终于有时间,也有勇气来写下这一篇总结.的确,这是我第一次正式的ACM线下赛,我本以为再不济,也可以拿个三等奖,没想到,实力打铁.确实对我打击比较大,以前的确是知道自己菜,但是,实在是没有想到自己竟然这么菜.好了,正式说下这次比赛吧! 集训之前,实验室安排是8月8日放假让我们回去休息几天,然后8月15日正式开始集训.但是,实验室事实上参加省赛的两个队的队员大部分都是没有回去(当然不包括我了,的确很惭愧,虽然的确是家里有事,需要我回去办).我是8月13晚上回的学校,

2017 ICPC区域赛(西安站)--- J题 LOL(DP)

题目链接 problem description 5 friends play LOL together . Every one should BAN one character and PICK one character . The enemy should BAN 55 characters and PICK 55 characters . All these 2020 heroes must be different . Every one can BAN any heroes by h

2017 GDCPC 省赛总结

第一年参加省赛,也是我接触acm半年多的第一个正式省级赛事,这半年来我为acm付出的可能很多,但经历过这次省赛后,给我唯一的感觉就是,还不够多. 直接分析题目吧,开始拿到试题后我读的是A题,然后我的队友好像是开始读BC,我读完A题就确定这是一道水题,然后没多加分析就开始写了,中间过程有很多的差错,导致我们差不多30多分钟才2A了这道水题,之前的一次WA是因为少输出了一个#号--.总而言之还是不太习惯这种大赛场面,由于被各种高校包围,所以我们全场基本都是在吵杂的讨论声度过的,导致读题及其难以专心.

2017年浙江省赛总结

最终是5题银.其实感觉再给点时间能7题的,主要是最后机子不够用了,没时间调试了,当然代码能力弱也是很大的一个问题. E题,队友当时卡了很久,最终是A了.赛后发现就是一个很水的数位DP..代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 using namespace std; 5 typedef long long ll; 6 7 int T,n; 8 char s[15]

2017端午欢乐赛——Day1T3(树的直径+并查集)

//前些天的和jdfz的神犇们联考的模拟赛.那天上午大概是没睡醒吧,考场上忘了写输出-1的情况,白丢了25分真是**. 题目描述     小C所在的城市有 n 个供电站,m条电线.相连的供电站会形成一个供电群,那么为了节省材料,供电群是一棵树的形式,也即城市是一个森林的形式(树:V个点,V-1条边的无向连通图,森林:若干棵树).每个供电群中不需要所有供电站都工作,最少只需要一个工作,其余的就都会通过电线收到电,从而完成自己的供电任务.当然,这样会产生延迟.定义两个供电站的延迟为它们之间的电线数量

hdu 6152 : Friend-Graph (2017 CCPC网络赛 1003)

题目链接 裸的结论题.百度 Ramsey定理.刚学过之后以为在哪也不会用到23333333333,没想到今天网络赛居然出了.顺利在题面更改前A掉~~~(我觉得要不是我开机慢+编译慢+中间暂时死机,我还能再早几分钟过掉它 #include<bits/stdc++.h> using namespace std; int g[8][8]; int n; void solve() { for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) for

2017师大省赛总结

5月11 12号黑龙江省赛ccpc,在师大举行. 师大真的好棒啊,理工的我去了师大就像乡下人进城了一样兴奋啊,师大有好多小姐姐啊,还是蛮漂亮的.但是省赛的衣服就有点那什么了,竟然是原谅绿色的,我一直都不敢相信,我印象中的战衣都是很帅气的(中二病犯了),怎么到我这里就变成原谅绿了,啊啊啊,好无奈.但是看校内dalao们东北赛的衣服是蓝色的(比原谅色好看多了)随着衣服还发了参赛证(这是我唯一感觉看着正常的东西了),然后就是宣传手册,后面还附了一张师大的地图(真的比理工大太多了,走一回我就累了,队友还

2017山东省省赛总结

每一次比赛都为自己的智商捉急,我能有什么办法,我也很绝望啊,这么笨我也很无奈啊,只能默默的膜拜. 比赛前几天天天晚上做梦,第一天梦见了zp.wyk和封老师:第二天梦到了卢老师.周老师和sxx:第三天梦到比赛的时候zp和wyk在我不知情的时候把题都a了,我目瞪口呆.jpg,然后拿了金牌(果然是做梦,还有好大一个flag). 比赛的时候简单题a完了以后,zp给我解释了一下D题,忘记谁说可能是矩阵快速幂,然后我推了半天以后感觉不是矩阵快速幂就让zp自己去想了,看了C题以后,yk很快想出了做法,然后他就

2017西安网络赛 计蒜客 Trig Function 切比雪夫多项式

http://www.docin.com/p-385138324.html 用以表示cosnx的关于cosx的多项式的通项公式 http://www.docin.com/p-232710665.html?docfrom=rrela 数列通项公式的求法(论文) 问答里说这个是切比雪夫多项式 我查了一下哇.. 第一类切比雪夫多项式 #include <stdio.h> #include <cstring> #include <iostream> #include <m