【题解】2015编程之美资格赛 CodeHunt C#满分参考与总结
2015-04-19 22:15
405 查看
去年(2014)编程之美我是靠着不熟练的C#,边做CodeHunt边查资料,跌跌撞撞进了复赛(当然进复赛以后没别人有技巧,没进线下,不然就醉了),当然没收藏好总结,有点遗憾——这个模式挺好玩的啊~于是今年就下定决心,做完以后整理一下所有题目的测试数据、我的代码和做题思路了~
先说明:我C#用的比Java熟,只愿意用C#写(虽然其实都不算太熟)
首先当然是资格赛的了
0.2
x和y做的运算?一般就是a*x+b*y+c的形式吧,套进去就行了
0.3
只能说,不难,这只是直觉,所写即所想……
0.4
我下面的代码,只是为了强行用foreach而这么写的,其实完全没必要……for循环修改a[]里的,负数就绝对值运算一下就行了。
0.5
找一下规律,发现要求第一次出现的下标,否则返回-1——string的IndexOf方法正好就是这种行为!
0.6
如果出现重复的数,返回true,否则返回false
一开始写了个,把数组排序,然后检查每个相邻两项是否相同——代码质量1灯
不得不说,C#的Linq太方便了!
对数组调用Distinct方法,返回一个IEnumerable<T>接口,然后ToArray()就变成去重的数组了,判断前后两者长度是否一样就行
0.7
这个题是有点逗你玩的意思
我本来以为是判断奇数的个数,奇数个返回1,偶数个返回0-_-||
后来多搞了一点数据出来发现,好像直接输出最后一个值就好了!
1.1
任务,比较明显的,就是把5位二进制字符串变成2位16进制字符串(不足的补上前导0)
我第一时间想到Java,因为的确用Java做过这件事情……可是,我可以吐槽一下,CodeHunt的Java简直是残次品吗?java.math.*没有是什么心态……
然后google查啊,然后就发现了我在代码里用到的下面这两个方法:
Convert.ToInt32
Int32.ToString()
他们可以做2、8、10、16进制之间的相互转换,没Java的凶悍(Java可以做2到36进制的),但这题上,够用了。
1.2
通过骗数据大法(函数里把给出的输入和对应输出都正确处理,提交,他会给你更多数据),发现结果就是4的倍数……
0,1,2,3-->0
4,5,6,7-->4
——这明显是整除4后乘4的行为
1.3
(有一种数字电路课程设计的既视感)
看到数据的第一反应是,3个中2个以上为true的就是true(3选2投票器)
然后提交,返回错误,多提供一组:
true , false, false -->true
于是问题变成了,如果把x,y,z看做二进制每一位,拼起来表达的数>=3为true,否则为false
于是可以写成x||(y&&z)了
1.4
灵感来源是," ! ! "-->{"",“!”,“!”,""}
这好像就是按空格分割的行为吧~
string的Split()大法好
1.5
简单的眼力和C#数组的考察
显然,生成一个m行n列的矩阵,每个元素[i][j]=(i+1)*(j+1)就行了
1.6
观察最后一组数据,从第一个字母开始,间隔1个字母取出来组成新串,且不取最后一个字母
这个题粗暴的表达就行了
2.1
又是找x和y关系的?
再试试看放到a*x+b*y+c的关系式里看看,又好像有一组符合的解啊
2.2
任务比较显然,在s串每两个字母中间插入一个p串
至于怎么写最短,就要看你是不是熟悉C#里String类的操作了
先用ToCharArray()方法变成字符数组,然后用Join()方法,轻松又愉快
——不熟悉的同学请拿起你的google,再不济,百度,搜一搜,看看msdn里的说明就行
2.3
又靠猜了……
先观察下面小的一组{15,0},{1,11}-->{15,165}
165=11*15
然后放到第二组里看看
472-13*10=342=19*18
于是第二维就是p[0]*q[1]+p[1]*q[0]
第一维,真的就靠神奇的瞎猜了,反正p、q的4个数都用上看看,就找到规律了
2.4
这题略神,构造了很多组数据,还是没找到什么好规律……
直到突然想看看,a尽量减去b,看看为true的都余下多少……
为true的都余下2!
就是说,判断a%b==2就行了!
2.5
把字母变成相应的2位十进制数,拼接起来,返回一个int
为什么要一开始ans="0"?防止产生的ans串是空串,直接去Parse()会出Exception
2.6
产生的结果好大啊……
我们除除看吧……
319935/462=692.5
692.5/462=1.49......... ==>这个方向仿佛不科学,换一个
692.5-462=230.5
而230.5=462/2-0.5
再来一组数据看看?
365807/494=740.5
740.5-494=246.5
而246.5=494/2-0.5
——恭喜,我们应该是找到规律了!
别忘了直接写表达式算出来double,强制类型转换就行了
======================难度提升分割线======================
上面的代码都还是很短的吧?用户写的内容不超过10行,规律比较好找,也好写一点
下面的难度是比上面的大一些的,拿来当复赛最后一题估计不过分的~
(不过还是比hihocoder水啊哈哈哈~)
3.1
任务:给你一个可能带有其他字符的括号串,不合法串返回0,否则返回最大括号嵌套深度
一开始感觉很虚啊,因为直觉告诉我,写完也得来个十多行,估计满灯不了~可是当我写完提交后发现,代码怎么长随便……
下面的方法太丑了——手工维护一个栈,里面存放左括号的位置,碰到左括号压栈,碰到右括号试图出栈,并且在左括号到右括号之间找最大括号深度,这对括号的最大深度就+1,最后判断整个过程中是否出现非法行为,如果有就返回0,否则返回最大括号深度。
——发誓,去年做编程之美的CodeHunt,我真的没碰到过代码要这么长的……
3.2
一开始看到这个题,我是拒绝的——这是什么鬼……,到底要做什么运算?于是跳过
可是回来一看,发现规律了:
b是你存的数据,a是需要的数据的下标,你返回a中请求的数据的查询结果值,组成个数组就行了……
不过有点小坑的是,a[]和b[]居然会传入同一个对象!你直接修改a再返回会得到错误答案(不过本来就不应该这样做的……)
3.3
这个任务挺诡异的——
要求找到在s中出现的所有p串,删除,其中最后一次出现p串的位置之后的字符也要删除
比如
"acba","acb"==>""
"bababjccccccccaba","ab"==>"bjcccccccc"
"bbb","bb"==>""
一种想法就是,先找LastIndexOf(),删掉之后的字符,然后再在剩下的s串中找p串,用Replace全部替换掉
——然后"bbb","bb"你想怎么办啊?
于是我采用了一种比较不科学的折衷方法:
先把所有p串换成###,然后删除最后一次###后面的字符,最后把所有###换成空,然后,好像就通过了?
(希望有大神给个更科学的正解,不胜感激~)
3.4
任务,找到x中出现的最大的质因子……
这个题就八仙过海,各显神通了,我这个写法应该不是最优的,请无视……
3.5
感觉好像做了什么很飘逸的运算产生的结果……
提示也很有意思,How is the array transformed?数组做了变换?
于是猜猜看,感觉是每项取了个平均值?
{0,18,30,40}-->{9,16,29,35}
9==(0+18)/2
16!=(0+30)/2;但16==(0+18+30)/3!!!
29=(18+30+40)/3
35=(30+40)/2
……怎么感觉像是图像处理里的均值滤波器啊(不过是一维的)
然后写一发啊,提交,过了
3.6
我发誓,没左上角的提示,还真的想不出来!
What happens to the bit pattern?
bit?感觉是二进制啊,于是:
Sample的二进制表示:
00000001
10000000
10000100
00100001
01100101
10100110
规律:二进制串做了个reverse操作
于是又来,把int变成8位2进制字符串,然后反转,再Convert.ToInt32转成整数形式。
不过,不知道为什么,CodeHunt上以下代码运行报错,不能用下面的办法反转原串(下面的办法网上找的,看着好科学)
char[] ret = data.ToCharArray();
return string.Concat<char>(ret.Reverse<char>());
那就折衷一下吧,变成字符数组,然后反转数组,你总没意见了吧?
===================================================
总结:
打完资格赛的CodeHunt,感觉是方方面面都要考啊!
C#要重点关注:
1、字符串的操作(字符串与数的转换,字符串的查找、替换、分割等)
2、数组的属性、方法
3、Linq带来的一些超省力的方法(比如Sum\Distinct\Min\Max\Zip等,有些地方不用Linq代码质量分拿不到3灯的)
然后还有就是自己平时的算法能力和实现能力的积累了
就是这样,End at 2015.04.20
先说明:我C#用的比Java熟,只愿意用C#写(虽然其实都不算太熟)
首先当然是资格赛的了
0.2
x和y做的运算?一般就是a*x+b*y+c的形式吧,套进去就行了
using System; public class Program { public static int Puzzle(int x, int y) { return 2*x+y; } }
0.3
只能说,不难,这只是直觉,所写即所想……
using System; public class Program { public static bool Puzzle(int x, int y) { return x>=y; } }
0.4
我下面的代码,只是为了强行用foreach而这么写的,其实完全没必要……for循环修改a[]里的,负数就绝对值运算一下就行了。
using System; using System.Collections.Generic; public class Program { public static int[] Puzzle( int[] a ) { List<int> t = new List<int>(); foreach (var i in a) { t.Add(i < 0 ? -i : i); } return t.ToArray(); } }
0.5
找一下规律,发现要求第一次出现的下标,否则返回-1——string的IndexOf方法正好就是这种行为!
using System; public class Program { public static int Puzzle(string s1, string s2) { return s1.IndexOf(s2); } }
0.6
如果出现重复的数,返回true,否则返回false
一开始写了个,把数组排序,然后检查每个相邻两项是否相同——代码质量1灯
不得不说,C#的Linq太方便了!
对数组调用Distinct方法,返回一个IEnumerable<T>接口,然后ToArray()就变成去重的数组了,判断前后两者长度是否一样就行
using System; using System.Linq; public class Program { public static bool Puzzle( int[] a ) { return a.Distinct().ToArray().Length!=a.Length; } }
0.7
这个题是有点逗你玩的意思
我本来以为是判断奇数的个数,奇数个返回1,偶数个返回0-_-||
后来多搞了一点数据出来发现,好像直接输出最后一个值就好了!
using System; public class Program { public static int Puzzle(int[] a) { return a[a.Length-1]; } }
1.1
任务,比较明显的,就是把5位二进制字符串变成2位16进制字符串(不足的补上前导0)
我第一时间想到Java,因为的确用Java做过这件事情……可是,我可以吐槽一下,CodeHunt的Java简直是残次品吗?java.math.*没有是什么心态……
然后google查啊,然后就发现了我在代码里用到的下面这两个方法:
Convert.ToInt32
Int32.ToString()
他们可以做2、8、10、16进制之间的相互转换,没Java的凶悍(Java可以做2到36进制的),但这题上,够用了。
using System; public class Program { public static string Puzzle(string x) { int ans=Convert.ToInt32(x,2); return ans.ToString("X2"); } }
1.2
通过骗数据大法(函数里把给出的输入和对应输出都正确处理,提交,他会给你更多数据),发现结果就是4的倍数……
0,1,2,3-->0
4,5,6,7-->4
——这明显是整除4后乘4的行为
using System; public class Program { public static int Puzzle(int n) { return n/4*4; } }
1.3
(有一种数字电路课程设计的既视感)
看到数据的第一反应是,3个中2个以上为true的就是true(3选2投票器)
然后提交,返回错误,多提供一组:
true , false, false -->true
于是问题变成了,如果把x,y,z看做二进制每一位,拼起来表达的数>=3为true,否则为false
于是可以写成x||(y&&z)了
using System; public class Program { public static bool Puzzle(bool x, bool y, bool z) { return x||y&&z; } }
1.4
灵感来源是," ! ! "-->{"",“!”,“!”,""}
这好像就是按空格分割的行为吧~
string的Split()大法好
using System; public class Program { public static string[] Puzzle(string s) { return s.Split(' '); } }
1.5
简单的眼力和C#数组的考察
显然,生成一个m行n列的矩阵,每个元素[i][j]=(i+1)*(j+1)就行了
using System; public class Program { public static int[][] Puzzle(int m, int n) { int [][]ans=new int[m][]; for(int i=0;i<m;i++){ ans[i]=new int ; for(int j=0;j<n;j++) ans[i][j]=(i+1)*(j+1); } return ans; } }
1.6
观察最后一组数据,从第一个字母开始,间隔1个字母取出来组成新串,且不取最后一个字母
这个题粗暴的表达就行了
using System; public class Program { public static string Puzzle(string s) { string ans=""; for(int i=0;i<s.Length-1;i+=2) ans+=s[i]; return ans; } }
2.1
又是找x和y关系的?
再试试看放到a*x+b*y+c的关系式里看看,又好像有一组符合的解啊
using System; public class Program { public static int Puzzle(int x, int y) { return x+2*y+3; } }
2.2
任务比较显然,在s串每两个字母中间插入一个p串
至于怎么写最短,就要看你是不是熟悉C#里String类的操作了
先用ToCharArray()方法变成字符数组,然后用Join()方法,轻松又愉快
——不熟悉的同学请拿起你的google,再不济,百度,搜一搜,看看msdn里的说明就行
using System; public class Program { public static string Puzzle(string s, string p) { return String.Join(p,s.ToCharArray()); } }
2.3
又靠猜了……
先观察下面小的一组{15,0},{1,11}-->{15,165}
165=11*15
然后放到第二组里看看
472-13*10=342=19*18
于是第二维就是p[0]*q[1]+p[1]*q[0]
第一维,真的就靠神奇的瞎猜了,反正p、q的4个数都用上看看,就找到规律了
using System; public static class Program { public static int[] Puzzle(int[] p, int[] q) { return new int[2]{p[0]*q[0]-p[1]*q[1] , p[0]*q[1]+p[1]*q[0]}; } }
2.4
这题略神,构造了很多组数据,还是没找到什么好规律……
直到突然想看看,a尽量减去b,看看为true的都余下多少……
为true的都余下2!
就是说,判断a%b==2就行了!
using System; public class Program { public static bool Puzzle(int a, int b) { return a%b==2; } }
2.5
把字母变成相应的2位十进制数,拼接起来,返回一个int
为什么要一开始ans="0"?防止产生的ans串是空串,直接去Parse()会出Exception
using System; public class Program { public static int Puzzle(string s) { string ans="0"; for(int i=0;i<s.Length;i++) ans+=((int)s[i]-96).ToString("D2"); return int.Parse(ans); } }
2.6
产生的结果好大啊……
我们除除看吧……
319935/462=692.5
692.5/462=1.49......... ==>这个方向仿佛不科学,换一个
692.5-462=230.5
而230.5=462/2-0.5
再来一组数据看看?
365807/494=740.5
740.5-494=246.5
而246.5=494/2-0.5
——恭喜,我们应该是找到规律了!
别忘了直接写表达式算出来double,强制类型转换就行了
using System; public class Program { public static int Puzzle(int x) { return (int)(x*(x+x/2.0-0.5)); } }
======================难度提升分割线======================
上面的代码都还是很短的吧?用户写的内容不超过10行,规律比较好找,也好写一点
下面的难度是比上面的大一些的,拿来当复赛最后一题估计不过分的~
(不过还是比hihocoder水啊哈哈哈~)
3.1
任务:给你一个可能带有其他字符的括号串,不合法串返回0,否则返回最大括号嵌套深度
一开始感觉很虚啊,因为直觉告诉我,写完也得来个十多行,估计满灯不了~可是当我写完提交后发现,代码怎么长随便……
下面的方法太丑了——手工维护一个栈,里面存放左括号的位置,碰到左括号压栈,碰到右括号试图出栈,并且在左括号到右括号之间找最大括号深度,这对括号的最大深度就+1,最后判断整个过程中是否出现非法行为,如果有就返回0,否则返回最大括号深度。
——发誓,去年做编程之美的CodeHunt,我真的没碰到过代码要这么长的……
using System; using System.Linq; public class Program { public static int Puzzle(string s) { int []dp=new int[s.Length]; int []stack=new int[s.Length]; int sp=0,mark=0; for(int i=0;i<s.Length;i++){ if(s[i]=='('){ stack[sp++]=i; }else if(s[i]==')'){ if(sp>0){ int m=0; for(int j=stack[sp-1]+1;j<i;j++) if(m<dp[j])m=dp[j]; dp[i]=m+1; sp--; }else mark=1; } } return mark==1||sp!=0?0:dp.Max(); } }
3.2
一开始看到这个题,我是拒绝的——这是什么鬼……,到底要做什么运算?于是跳过
可是回来一看,发现规律了:
b是你存的数据,a是需要的数据的下标,你返回a中请求的数据的查询结果值,组成个数组就行了……
不过有点小坑的是,a[]和b[]居然会传入同一个对象!你直接修改a再返回会得到错误答案(不过本来就不应该这样做的……)
using System; public static class Program { public static int[] Puzzle(int[] a, int[] b) { int []ans=new int[a.Length]; for(int i=0;i<a.Length;i++) ans[i]=b[a[i]]; return ans; } }
3.3
这个任务挺诡异的——
要求找到在s中出现的所有p串,删除,其中最后一次出现p串的位置之后的字符也要删除
比如
"acba","acb"==>""
"bababjccccccccaba","ab"==>"bjcccccccc"
"bbb","bb"==>""
一种想法就是,先找LastIndexOf(),删掉之后的字符,然后再在剩下的s串中找p串,用Replace全部替换掉
——然后"bbb","bb"你想怎么办啊?
于是我采用了一种比较不科学的折衷方法:
先把所有p串换成###,然后删除最后一次###后面的字符,最后把所有###换成空,然后,好像就通过了?
(希望有大神给个更科学的正解,不胜感激~)
using System; public class Program { public static string Puzzle(string s, string p) { if(p.Length==0)return s; s=s.Replace(p,"###"); if(s.LastIndexOf("###")>=0)s=s.Remove(s.LastIndexOf("###")); s=s.Replace("###",""); return s; } }
3.4
任务,找到x中出现的最大的质因子……
这个题就八仙过海,各显神通了,我这个写法应该不是最优的,请无视……
using System; public class Program { public static int Puzzle(int x) { if(x<4)return x; int maxp=1; for(int i=2;i<=Math.Sqrt(x);i++) while(x%i==0){ maxp=i; x/=i; } return maxp>x?maxp:x; } }
3.5
感觉好像做了什么很飘逸的运算产生的结果……
提示也很有意思,How is the array transformed?数组做了变换?
于是猜猜看,感觉是每项取了个平均值?
{0,18,30,40}-->{9,16,29,35}
9==(0+18)/2
16!=(0+30)/2;但16==(0+18+30)/3!!!
29=(18+30+40)/3
35=(30+40)/2
……怎么感觉像是图像处理里的均值滤波器啊(不过是一维的)
然后写一发啊,提交,过了
using System; public class Program { public static int[] Puzzle(int[] a) { int []b=new int[a.Length]; b[0]=(a[0]+a[1])/2; for(int i=1;i<a.Length-1;i++) b[i]=(a[i-1]+a[i]+a[i+1])/3; b[a.Length-1]=(a[a.Length-2]+a[a.Length-1])/2; return b; } }
3.6
我发誓,没左上角的提示,还真的想不出来!
What happens to the bit pattern?
bit?感觉是二进制啊,于是:
Sample的二进制表示:
00000001
10000000
10000100
00100001
01100101
10100110
规律:二进制串做了个reverse操作
于是又来,把int变成8位2进制字符串,然后反转,再Convert.ToInt32转成整数形式。
不过,不知道为什么,CodeHunt上以下代码运行报错,不能用下面的办法反转原串(下面的办法网上找的,看着好科学)
char[] ret = data.ToCharArray();
return string.Concat<char>(ret.Reverse<char>());
那就折衷一下吧,变成字符数组,然后反转数组,你总没意见了吧?
using System; public static class Program { public static int Puzzle(int n) { char []arr=Convert.ToString(n,2).PadLeft(8, '0').ToCharArray(); Array.Reverse(arr); return Convert.ToInt32(new string(arr),2); } }
===================================================
总结:
打完资格赛的CodeHunt,感觉是方方面面都要考啊!
C#要重点关注:
1、字符串的操作(字符串与数的转换,字符串的查找、替换、分割等)
2、数组的属性、方法
3、Linq带来的一些超省力的方法(比如Sum\Distinct\Min\Max\Zip等,有些地方不用Linq代码质量分拿不到3灯的)
然后还有就是自己平时的算法能力和实现能力的积累了
就是这样,End at 2015.04.20
相关文章推荐
- 【题解】2015编程之美初赛第二场 CodeHunt C#参考与总结
- 【又见C#】CH常用战略回忆 _CodeHunt战场 @ 编程之美2015资格赛
- 2015NOIP普级组第一题--金币(参考洛谷题解)
- 2015编程之美资格赛:2月29日
- 2015编程之美资格赛:基站选址 暴力
- 2015编程之美资格赛 A 2月29日
- 2015编程之美资格赛题目1 : 2月29日 分类: 算法 2015-04-21 11:28 27人阅读 评论(0) 收藏
- 看陈广老师c#参考视频总结(第十篇 完)
- hiho 编程之美2015资格赛(2月29日-模拟日期)
- 编程之美2015资格赛 解题报告
- 编程之美2015资格赛 C.基站选址
- 编程之美2015 资格赛 hihocoder 题目2: 回文字符序列
- 2015编程之美资格赛:回文子序列数 DP
- 编程之美2015资格赛 题目1 : 2月29日
- 2015编程之美资格赛题目1 : 2月29日
- 【Linq】C#的学习旅程 _2015编程之美挑战赛初赛 CodeHunt赛区
- 编程之美2015资格赛-回文子序列个数题解
- Google Code Jam 2015资格赛
- C# 条形码 生成函数 (Code 128 标准参考:GB/T 18347-2001)
- 2015编程之美资格赛B